mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Experimental work on a fragment-based encrypt activity
This commit is contained in:
parent
8f2abf36f8
commit
4c3506f4b1
@ -22,23 +22,13 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.view.PagerTabStrip;
|
import android.support.v4.view.PagerTabStrip;
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
|
||||||
import com.devspark.appmsg.AppMsg;
|
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
||||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
@ -47,7 +37,6 @@ import java.util.regex.Matcher;
|
|||||||
public class DecryptActivity extends DrawerActivity {
|
public class DecryptActivity extends DrawerActivity {
|
||||||
|
|
||||||
/* Intents */
|
/* Intents */
|
||||||
// without permission
|
|
||||||
public static final String ACTION_DECRYPT = Constants.INTENT_PREFIX + "DECRYPT";
|
public static final String ACTION_DECRYPT = Constants.INTENT_PREFIX + "DECRYPT";
|
||||||
|
|
||||||
/* EXTRA keys for input */
|
/* EXTRA keys for input */
|
||||||
@ -64,9 +53,7 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
private static final int PAGER_TAB_MESSAGE = 0;
|
private static final int PAGER_TAB_MESSAGE = 0;
|
||||||
private static final int PAGER_TAB_FILE = 1;
|
private static final int PAGER_TAB_FILE = 1;
|
||||||
|
|
||||||
|
|
||||||
private void initView() {
|
private void initView() {
|
||||||
// Pager
|
|
||||||
mViewPager = (ViewPager) findViewById(R.id.decrypt_pager);
|
mViewPager = (ViewPager) findViewById(R.id.decrypt_pager);
|
||||||
mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip);
|
mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -49,20 +49,19 @@ import java.io.File;
|
|||||||
public class DecryptFileFragment extends DecryptFragment {
|
public class DecryptFileFragment extends DecryptFragment {
|
||||||
public static final String ARG_FILENAME = "filename";
|
public static final String ARG_FILENAME = "filename";
|
||||||
|
|
||||||
|
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||||
|
|
||||||
|
// view
|
||||||
private EditText mFilename;
|
private EditText mFilename;
|
||||||
private CheckBox mDeleteAfter;
|
private CheckBox mDeleteAfter;
|
||||||
private BootstrapButton mBrowse;
|
private BootstrapButton mBrowse;
|
||||||
private BootstrapButton mDecryptButton;
|
private BootstrapButton mDecryptButton;
|
||||||
|
|
||||||
|
|
||||||
private String mInputFilename = null;
|
private String mInputFilename = null;
|
||||||
private String mOutputFilename = null;
|
private String mOutputFilename = null;
|
||||||
|
|
||||||
private FileDialogFragment mFileDialog;
|
private FileDialogFragment mFileDialog;
|
||||||
|
|
||||||
private static final int RESULT_CODE_FILE = 0x00007003;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inflate the layout for this fragment
|
* Inflate the layout for this fragment
|
||||||
*/
|
*/
|
||||||
@ -72,14 +71,14 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
|
|
||||||
mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename);
|
mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename);
|
||||||
mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse);
|
mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse);
|
||||||
|
mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);
|
||||||
|
mDecryptButton = (BootstrapButton) view.findViewById(R.id.decrypt_file_action_decrypt);
|
||||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||||
RESULT_CODE_FILE);
|
RESULT_CODE_FILE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);
|
|
||||||
mDecryptButton = (BootstrapButton) view.findViewById(R.id.decrypt_file_action_decrypt);
|
|
||||||
mDecryptButton.setOnClickListener(new View.OnClickListener() {
|
mDecryptButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -87,12 +86,17 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
String filename = getArguments().getString(ARG_FILENAME);
|
String filename = getArguments().getString(ARG_FILENAME);
|
||||||
if (filename != null) {
|
if (filename != null) {
|
||||||
mFilename.setText(filename);
|
mFilename.setText(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void guessOutputFilename() {
|
private void guessOutputFilename() {
|
||||||
@ -193,14 +197,12 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
// get returned data bundle
|
// get returned data bundle
|
||||||
Bundle returnData = message.getData();
|
Bundle returnData = message.getData();
|
||||||
|
|
||||||
|
|
||||||
PgpDecryptVerifyResult decryptVerifyResult =
|
PgpDecryptVerifyResult decryptVerifyResult =
|
||||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||||
|
|
||||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (mDeleteAfter.isChecked()) {
|
if (mDeleteAfter.isChecked()) {
|
||||||
// Create and show dialog to delete original file
|
// Create and show dialog to delete original file
|
||||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||||
@ -208,13 +210,11 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||||
|
|
||||||
// display signature result in activity
|
// display signature result in activity
|
||||||
onSignatureResult(signatureResult);
|
onSignatureResult(signatureResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -187,6 +187,10 @@ public class DecryptFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be overridden by MessageFragment and FileFragment to start actual decryption
|
||||||
|
* @param passphrase
|
||||||
|
*/
|
||||||
protected void decryptStart(String passphrase) {
|
protected void decryptStart(String passphrase) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -50,7 +50,6 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
private BootstrapButton mDecryptButton;
|
private BootstrapButton mDecryptButton;
|
||||||
private BootstrapButton mDecryptFromCLipboardButton;
|
private BootstrapButton mDecryptFromCLipboardButton;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inflate the layout for this fragment
|
* Inflate the layout for this fragment
|
||||||
*/
|
*/
|
||||||
@ -61,14 +60,12 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
mMessage = (EditText) view.findViewById(R.id.message);
|
mMessage = (EditText) view.findViewById(R.id.message);
|
||||||
mDecryptButton = (BootstrapButton) view.findViewById(R.id.action_decrypt);
|
mDecryptButton = (BootstrapButton) view.findViewById(R.id.action_decrypt);
|
||||||
mDecryptFromCLipboardButton = (BootstrapButton) view.findViewById(R.id.action_decrypt_from_clipboard);
|
mDecryptFromCLipboardButton = (BootstrapButton) view.findViewById(R.id.action_decrypt_from_clipboard);
|
||||||
|
|
||||||
mDecryptButton.setOnClickListener(new OnClickListener() {
|
mDecryptButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
decryptStart(null);
|
decryptStart(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() {
|
mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -93,6 +90,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
private void decryptFromClipboard() {
|
private void decryptFromClipboard() {
|
||||||
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
|
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
|
||||||
|
|
||||||
|
// only decrypt if clipboard content is available and a pgp message or cleartext signature
|
||||||
if (clipboardText != null) {
|
if (clipboardText != null) {
|
||||||
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText);
|
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText);
|
||||||
if (!matcher.matches()) {
|
if (!matcher.matches()) {
|
||||||
@ -146,14 +144,12 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
// get returned data bundle
|
// get returned data bundle
|
||||||
Bundle returnData = message.getData();
|
Bundle returnData = message.getData();
|
||||||
|
|
||||||
|
|
||||||
PgpDecryptVerifyResult decryptVerifyResult =
|
PgpDecryptVerifyResult decryptVerifyResult =
|
||||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||||
|
|
||||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
||||||
AppMsg.STYLE_INFO).show();
|
AppMsg.STYLE_INFO).show();
|
||||||
|
|
||||||
@ -162,13 +158,11 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
mMessage.setText(new String(decryptedMessage));
|
mMessage.setText(new String(decryptedMessage));
|
||||||
mMessage.setHorizontallyScrolling(false);
|
mMessage.setHorizontallyScrolling(false);
|
||||||
|
|
||||||
|
|
||||||
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||||
|
|
||||||
// display signature result in activity
|
// display signature result in activity
|
||||||
onSignatureResult(signatureResult);
|
onSignatureResult(signatureResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -184,5 +178,4 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
getActivity().startService(intent);
|
getActivity().startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
|
|||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
|
||||||
|
public interface EncryptActivityInterface {
|
||||||
|
|
||||||
|
public boolean isModeSymmetric();
|
||||||
|
|
||||||
|
public long getSignatureKey();
|
||||||
|
public long[] getEncryptionKeys();
|
||||||
|
|
||||||
|
public String getPassphrase();
|
||||||
|
public String getPassphraseAgain();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
public class EncryptAsymmetricFragment extends Fragment {
|
||||||
|
public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id";
|
||||||
|
public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids";
|
||||||
|
|
||||||
|
public static final int RESULT_CODE_PUBLIC_KEYS = 0x00007001;
|
||||||
|
public static final int RESULT_CODE_SECRET_KEYS = 0x00007002;
|
||||||
|
|
||||||
|
OnAsymmetricKeySelection mKeySelectionListener;
|
||||||
|
|
||||||
|
// view
|
||||||
|
private BootstrapButton mSelectKeysButton;
|
||||||
|
private CheckBox mSign;
|
||||||
|
private TextView mMainUserId;
|
||||||
|
private TextView mMainUserIdRest;
|
||||||
|
|
||||||
|
// model
|
||||||
|
private long mSecretKeyId = Id.key.none;
|
||||||
|
private long mEncryptionKeyIds[] = null;
|
||||||
|
|
||||||
|
// Container Activity must implement this interface
|
||||||
|
public interface OnAsymmetricKeySelection {
|
||||||
|
public void onSigningKeySelected(long signingKeyId);
|
||||||
|
|
||||||
|
public void onEncryptionKeysSelected(long[] encryptionKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
try {
|
||||||
|
mKeySelectionListener = (OnAsymmetricKeySelection) activity;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException(activity.toString() + " must implement OnAsymmetricKeySelection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSignatureKeyId(long signatureKeyId) {
|
||||||
|
mSecretKeyId = signatureKeyId;
|
||||||
|
mKeySelectionListener.onSigningKeySelected(signatureKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setEncryptionKeyIds(long[] encryptionKeyIds) {
|
||||||
|
mEncryptionKeyIds = encryptionKeyIds;
|
||||||
|
mKeySelectionListener.onEncryptionKeysSelected(encryptionKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflate the layout for this fragment
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
|
||||||
|
|
||||||
|
mSelectKeysButton = (BootstrapButton) view.findViewById(R.id.btn_selectEncryptKeys);
|
||||||
|
mSign = (CheckBox) view.findViewById(R.id.sign);
|
||||||
|
mMainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
||||||
|
mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
|
||||||
|
mSelectKeysButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
selectPublicKeys();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mSign.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
CheckBox checkBox = (CheckBox) v;
|
||||||
|
if (checkBox.isChecked()) {
|
||||||
|
selectSecretKey();
|
||||||
|
} else {
|
||||||
|
setSignatureKeyId(Id.key.none);
|
||||||
|
updateView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
|
long signatureKeyId = getArguments().getLong(ARG_SIGNATURE_KEY_ID);
|
||||||
|
long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS);
|
||||||
|
|
||||||
|
// preselect keys given by arguments (given by Intent to EncryptActivity)
|
||||||
|
preselectKeys(signatureKeyId, encryptionKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If an Intent gives a signatureKeyId and/or encryptionKeyIds, preselect those!
|
||||||
|
*
|
||||||
|
* @param preselectedSignatureKeyId
|
||||||
|
* @param preselectedEncryptionKeyIds
|
||||||
|
*/
|
||||||
|
private void preselectKeys(long preselectedSignatureKeyId, long[] preselectedEncryptionKeyIds) {
|
||||||
|
if (preselectedSignatureKeyId != 0) {
|
||||||
|
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(getActivity(),
|
||||||
|
preselectedSignatureKeyId);
|
||||||
|
PGPSecretKey masterKey;
|
||||||
|
if (keyRing != null) {
|
||||||
|
masterKey = PgpKeyHelper.getMasterKey(keyRing);
|
||||||
|
if (masterKey != null) {
|
||||||
|
Vector<PGPSecretKey> signKeys = PgpKeyHelper.getUsableSigningKeys(keyRing);
|
||||||
|
if (signKeys.size() > 0) {
|
||||||
|
setSignatureKeyId(masterKey.getKeyID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preselectedEncryptionKeyIds != null) {
|
||||||
|
Vector<Long> goodIds = new Vector<Long>();
|
||||||
|
for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
|
||||||
|
PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(getActivity(),
|
||||||
|
preselectedEncryptionKeyIds[i]);
|
||||||
|
PGPPublicKey masterKey;
|
||||||
|
if (keyRing == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
masterKey = PgpKeyHelper.getMasterKey(keyRing);
|
||||||
|
if (masterKey == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vector<PGPPublicKey> encryptKeys = PgpKeyHelper.getUsableEncryptKeys(keyRing);
|
||||||
|
if (encryptKeys.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goodIds.add(masterKey.getKeyID());
|
||||||
|
}
|
||||||
|
if (goodIds.size() > 0) {
|
||||||
|
long[] keyIds = new long[goodIds.size()];
|
||||||
|
for (int i = 0; i < goodIds.size(); ++i) {
|
||||||
|
keyIds[i] = goodIds.get(i);
|
||||||
|
}
|
||||||
|
setEncryptionKeyIds(keyIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateView() {
|
||||||
|
if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) {
|
||||||
|
mSelectKeysButton.setText(getString(R.string.select_keys_button_default));
|
||||||
|
} else {
|
||||||
|
mSelectKeysButton.setText(getResources().getQuantityString(
|
||||||
|
R.plurals.select_keys_button, mEncryptionKeyIds.length,
|
||||||
|
mEncryptionKeyIds.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSecretKeyId == Id.key.none) {
|
||||||
|
mSign.setChecked(false);
|
||||||
|
mMainUserId.setText("");
|
||||||
|
mMainUserIdRest.setText("");
|
||||||
|
} else {
|
||||||
|
String uid = getResources().getString(R.string.user_id_no_name);
|
||||||
|
String uidExtra = "";
|
||||||
|
// TODO: make it nice and use helper!
|
||||||
|
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(getActivity(),
|
||||||
|
mSecretKeyId);
|
||||||
|
if (keyRing != null) {
|
||||||
|
PGPSecretKey key = PgpKeyHelper.getMasterKey(keyRing);
|
||||||
|
if (key != null) {
|
||||||
|
String userId = PgpKeyHelper.getMainUserIdSafe(getActivity(), key);
|
||||||
|
String chunks[] = userId.split(" <", 2);
|
||||||
|
uid = chunks[0];
|
||||||
|
if (chunks.length > 1) {
|
||||||
|
uidExtra = "<" + chunks[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMainUserId.setText(uid);
|
||||||
|
mMainUserIdRest.setText(uidExtra);
|
||||||
|
mSign.setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
// updateActionBarButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectPublicKeys() {
|
||||||
|
Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class);
|
||||||
|
Vector<Long> keyIds = new Vector<Long>();
|
||||||
|
if (mSecretKeyId != 0) {
|
||||||
|
keyIds.add(mSecretKeyId);
|
||||||
|
}
|
||||||
|
if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) {
|
||||||
|
for (int i = 0; i < mEncryptionKeyIds.length; ++i) {
|
||||||
|
keyIds.add(mEncryptionKeyIds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long[] initialKeyIds = null;
|
||||||
|
if (keyIds.size() > 0) {
|
||||||
|
initialKeyIds = new long[keyIds.size()];
|
||||||
|
for (int i = 0; i < keyIds.size(); ++i) {
|
||||||
|
initialKeyIds[i] = keyIds.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intent.putExtra(SelectPublicKeyActivity.EXTRA_SELECTED_MASTER_KEY_IDS, initialKeyIds);
|
||||||
|
startActivityForResult(intent, Id.request.public_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSecretKey() {
|
||||||
|
Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class);
|
||||||
|
startActivityForResult(intent, Id.request.secret_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
|
||||||
|
case RESULT_CODE_PUBLIC_KEYS: {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
Bundle bundle = data.getExtras();
|
||||||
|
setEncryptionKeyIds(bundle
|
||||||
|
.getLongArray(SelectPublicKeyActivity.RESULT_EXTRA_MASTER_KEY_IDS));
|
||||||
|
}
|
||||||
|
updateView();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RESULT_CODE_SECRET_KEYS: {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
Uri uri_master_key = data.getData();
|
||||||
|
setSignatureKeyId(Long.valueOf(uri_master_key.getLastPathSegment()));
|
||||||
|
} else {
|
||||||
|
setSignatureKeyId(Id.key.none);
|
||||||
|
}
|
||||||
|
updateView();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||||
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.util.Choice;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class EncryptFileFragment extends Fragment {
|
||||||
|
public static final String ARG_FILENAME = "filename";
|
||||||
|
public static final String ARG_ASCII_ARMOR = "ascii_armor";
|
||||||
|
|
||||||
|
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||||
|
|
||||||
|
private EncryptActivityInterface mEncryptInterface;
|
||||||
|
|
||||||
|
// view
|
||||||
|
private CheckBox mAsciiArmor = null;
|
||||||
|
private Spinner mFileCompression = null;
|
||||||
|
private EditText mFilename = null;
|
||||||
|
private CheckBox mDeleteAfter = null;
|
||||||
|
private CheckBox mShareAfter = null;
|
||||||
|
private BootstrapButton mBrowse = null;
|
||||||
|
private BootstrapButton mEncryptFile;
|
||||||
|
|
||||||
|
private FileDialogFragment mFileDialog;
|
||||||
|
|
||||||
|
// model
|
||||||
|
private String mInputFilename = null;
|
||||||
|
private String mOutputFilename = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
try {
|
||||||
|
mEncryptInterface = (EncryptActivityInterface) activity;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflate the layout for this fragment
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.encrypt_file_fragment, container, false);
|
||||||
|
|
||||||
|
mEncryptFile = (BootstrapButton) view.findViewById(R.id.action_encrypt_file);
|
||||||
|
mEncryptFile.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
encryptClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mFilename = (EditText) view.findViewById(R.id.filename);
|
||||||
|
mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse);
|
||||||
|
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||||
|
Id.request.filename);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mFileCompression = (Spinner) view.findViewById(R.id.fileCompression);
|
||||||
|
Choice[] choices = new Choice[]{
|
||||||
|
new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " ("
|
||||||
|
+ getString(R.string.compression_fast) + ")"),
|
||||||
|
new Choice(Id.choice.compression.zip, "ZIP ("
|
||||||
|
+ getString(R.string.compression_fast) + ")"),
|
||||||
|
new Choice(Id.choice.compression.zlib, "ZLIB ("
|
||||||
|
+ getString(R.string.compression_fast) + ")"),
|
||||||
|
new Choice(Id.choice.compression.bzip2, "BZIP2 ("
|
||||||
|
+ getString(R.string.compression_very_slow) + ")"),};
|
||||||
|
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getActivity(),
|
||||||
|
android.R.layout.simple_spinner_item, choices);
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
mFileCompression.setAdapter(adapter);
|
||||||
|
|
||||||
|
int defaultFileCompression = Preferences.getPreferences(getActivity()).getDefaultFileCompression();
|
||||||
|
for (int i = 0; i < choices.length; ++i) {
|
||||||
|
if (choices[i].getId() == defaultFileCompression) {
|
||||||
|
mFileCompression.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDeleteAfter = (CheckBox) view.findViewById(R.id.deleteAfterEncryption);
|
||||||
|
mShareAfter = (CheckBox) view.findViewById(R.id.shareAfterEncryption);
|
||||||
|
|
||||||
|
mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmour);
|
||||||
|
mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmour());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
|
String filename = getArguments().getString(ARG_FILENAME);
|
||||||
|
if (filename != null) {
|
||||||
|
mFilename.setText(filename);
|
||||||
|
}
|
||||||
|
boolean asciiArmor = getArguments().getBoolean(ARG_ASCII_ARMOR);
|
||||||
|
if (asciiArmor) {
|
||||||
|
mAsciiArmor.setChecked(asciiArmor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guess output filename based on input path
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @return Suggestion for output filename
|
||||||
|
*/
|
||||||
|
private String guessOutputFilename(String path) {
|
||||||
|
// output in the same directory but with additional ending
|
||||||
|
File file = new File(path);
|
||||||
|
String ending = (mAsciiArmor.isChecked() ? ".asc" : ".gpg");
|
||||||
|
String outputFilename = file.getParent() + File.separator + file.getName() + ending;
|
||||||
|
|
||||||
|
return outputFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showOutputFileDialog() {
|
||||||
|
// Message is received after file is selected
|
||||||
|
Handler returnHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||||
|
Bundle data = message.getData();
|
||||||
|
mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||||
|
encryptStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
|
|
||||||
|
mFileDialog = FileDialogFragment.newInstance(messenger,
|
||||||
|
getString(R.string.title_encrypt_to_file),
|
||||||
|
getString(R.string.specify_file_to_encrypt_to), mOutputFilename, null);
|
||||||
|
|
||||||
|
mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encryptClicked() {
|
||||||
|
String currentFilename = mFilename.getText().toString();
|
||||||
|
if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
|
||||||
|
mInputFilename = mFilename.getText().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
mOutputFilename = guessOutputFilename(mInputFilename);
|
||||||
|
|
||||||
|
if (mInputFilename.equals("")) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mInputFilename.startsWith("content")) {
|
||||||
|
File file = new File(mInputFilename);
|
||||||
|
if (!file.exists() || !file.isFile()) {
|
||||||
|
AppMsg.makeText(
|
||||||
|
getActivity(),
|
||||||
|
getString(R.string.error_message,
|
||||||
|
getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEncryptInterface.isModeSymmetric()) {
|
||||||
|
// symmetric encryption
|
||||||
|
|
||||||
|
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean gotPassPhrase = (mEncryptInterface.getPassphrase().length() != 0);
|
||||||
|
if (!gotPassPhrase) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// asymmetric encryption
|
||||||
|
|
||||||
|
boolean encryptIt = (mEncryptInterface.getEncryptionKeys() != null
|
||||||
|
&& mEncryptInterface.getEncryptionKeys().length > 0);
|
||||||
|
// for now require at least one form of encryption for files
|
||||||
|
if (!encryptIt) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.select_encryption_key, AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encryptIt && mEncryptInterface.getSignatureKey() == 0) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
|
||||||
|
AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEncryptInterface.getSignatureKey() != 0
|
||||||
|
&& PassphraseCacheService.getCachedPassphrase(getActivity(), mEncryptInterface.getSignatureKey()) == null) {
|
||||||
|
showPassphraseDialog();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showOutputFileDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encryptStart() {
|
||||||
|
// Send all information needed to service to edit key in other thread
|
||||||
|
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
|
||||||
|
|
||||||
|
// fill values for this action
|
||||||
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
|
boolean useAsciiArmor = true;
|
||||||
|
long encryptionKeyIds[] = null;
|
||||||
|
int compressionId = 0;
|
||||||
|
boolean signOnly = false;
|
||||||
|
long mSecretKeyIdToPass = 0;
|
||||||
|
|
||||||
|
if (mEncryptInterface.isModeSymmetric()) {
|
||||||
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
|
String passphrase = mEncryptInterface.getPassphrase();
|
||||||
|
if (passphrase.length() == 0) {
|
||||||
|
passphrase = null;
|
||||||
|
}
|
||||||
|
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase);
|
||||||
|
} else {
|
||||||
|
mSecretKeyIdToPass = mEncryptInterface.getSignatureKey();
|
||||||
|
encryptionKeyIds = mEncryptInterface.getEncryptionKeys();
|
||||||
|
signOnly = (mEncryptInterface.getEncryptionKeys() == null
|
||||||
|
|| mEncryptInterface.getEncryptionKeys().length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
|
||||||
|
|
||||||
|
// choose default settings, target and data bundle by target
|
||||||
|
useAsciiArmor = mAsciiArmor.isChecked();
|
||||||
|
compressionId = ((Choice) mFileCompression.getSelectedItem()).getId();
|
||||||
|
|
||||||
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI);
|
||||||
|
|
||||||
|
Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename="
|
||||||
|
+ mOutputFilename);
|
||||||
|
|
||||||
|
data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename);
|
||||||
|
data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename);
|
||||||
|
|
||||||
|
|
||||||
|
data.putLong(KeychainIntentService.ENCRYPT_SECRET_KEY_ID, mSecretKeyIdToPass);
|
||||||
|
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, useAsciiArmor);
|
||||||
|
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, encryptionKeyIds);
|
||||||
|
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
|
||||||
|
// data.putBoolean(KeychainIntentService.ENCRYPT_GENERATE_SIGNATURE, mGenerateSignature);
|
||||||
|
data.putBoolean(KeychainIntentService.ENCRYPT_SIGN_ONLY, signOnly);
|
||||||
|
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
|
||||||
|
// Message is received after encrypting is done in KeychainIntentService
|
||||||
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
|
||||||
|
getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
// handle messages by standard KeychainIntentServiceHandler first
|
||||||
|
super.handleMessage(message);
|
||||||
|
|
||||||
|
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||||
|
// get returned data bundle
|
||||||
|
Bundle data = message.getData();
|
||||||
|
|
||||||
|
String output;
|
||||||
|
AppMsg.makeText(getActivity(), R.string.encryption_successful,
|
||||||
|
AppMsg.STYLE_INFO).show();
|
||||||
|
|
||||||
|
if (mDeleteAfter.isChecked()) {
|
||||||
|
// Create and show dialog to delete original file
|
||||||
|
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||||
|
.newInstance(mInputFilename);
|
||||||
|
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShareAfter.isChecked()) {
|
||||||
|
// Share encrypted file
|
||||||
|
Intent sendFileIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
sendFileIntent.setType("*/*");
|
||||||
|
sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename));
|
||||||
|
startActivity(Intent.createChooser(sendFileIntent,
|
||||||
|
getString(R.string.title_send_file)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(saveHandler);
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
|
||||||
|
|
||||||
|
// show progress dialog
|
||||||
|
saveHandler.showProgressDialog(getActivity());
|
||||||
|
|
||||||
|
// start service with intent
|
||||||
|
getActivity().startService(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case RESULT_CODE_FILE: {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
|
try {
|
||||||
|
String path = FileHelper.getPath(getActivity(), data.getData());
|
||||||
|
Log.d(Constants.TAG, "path=" + path);
|
||||||
|
|
||||||
|
mFilename.setText(path);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
Log.e(Constants.TAG, "Nullpointer while retrieving path!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows passphrase dialog to cache a new passphrase the user enters for using it later for
|
||||||
|
* encryption
|
||||||
|
*/
|
||||||
|
private void showPassphraseDialog() {
|
||||||
|
// Message is received after passphrase is cached
|
||||||
|
Handler returnHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||||
|
showOutputFileDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
|
|
||||||
|
try {
|
||||||
|
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||||
|
getActivity(), messenger, mEncryptInterface.getSignatureKey());
|
||||||
|
|
||||||
|
passphraseDialog.show(getActivity().getSupportFragmentManager(), "passphraseDialog");
|
||||||
|
} catch (PgpGeneralException e) {
|
||||||
|
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
|
||||||
|
// send message to handler to start encryption directly
|
||||||
|
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
public class EncryptMessageFragment extends Fragment {
|
||||||
|
public static final String ARG_TEXT = "text";
|
||||||
|
|
||||||
|
private EditText mMessage = null;
|
||||||
|
private BootstrapButton mEncryptShare;
|
||||||
|
private BootstrapButton mEncryptClipboard;
|
||||||
|
|
||||||
|
private EncryptActivityInterface mEncryptInterface;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
try {
|
||||||
|
mEncryptInterface = (EncryptActivityInterface) activity;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflate the layout for this fragment
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false);
|
||||||
|
|
||||||
|
mMessage = (EditText) view.findViewById(R.id.message);
|
||||||
|
mEncryptClipboard = (BootstrapButton) view.findViewById(R.id.action_encrypt_clipboard);
|
||||||
|
mEncryptShare = (BootstrapButton) view.findViewById(R.id.action_encrypt_share);
|
||||||
|
mEncryptClipboard.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
encryptClicked(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mEncryptShare.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
encryptClicked(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
|
String text = getArguments().getString(ARG_TEXT);
|
||||||
|
if (text != null) {
|
||||||
|
mMessage.setText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes bad message characters for gmail
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String fixBadCharactersForGmail(String message) {
|
||||||
|
// fix the message a bit, trailing spaces and newlines break stuff,
|
||||||
|
// because GMail sends as HTML and such things fuck up the
|
||||||
|
// signature,
|
||||||
|
// TODO: things like "<" and ">" also fuck up the signature
|
||||||
|
message = message.replaceAll(" +\n", "\n");
|
||||||
|
message = message.replaceAll("\n\n+", "\n\n");
|
||||||
|
message = message.replaceFirst("^\n+", "");
|
||||||
|
// make sure there'll be exactly one newline at the end
|
||||||
|
message = message.replaceFirst("\n*$", "\n");
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encryptClicked(boolean toClipboard) {
|
||||||
|
if (mEncryptInterface.isModeSymmetric()) {
|
||||||
|
// symmetric encryption
|
||||||
|
|
||||||
|
boolean gotPassPhrase = false;
|
||||||
|
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gotPassPhrase = (mEncryptInterface.getPassphrase().length() != 0);
|
||||||
|
if (!gotPassPhrase) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// asymmetric encryption
|
||||||
|
|
||||||
|
boolean encryptIt = (mEncryptInterface.getEncryptionKeys() != null
|
||||||
|
&& mEncryptInterface.getEncryptionKeys().length > 0);
|
||||||
|
|
||||||
|
if (!encryptIt && mEncryptInterface.getSignatureKey() == 0) {
|
||||||
|
AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
|
||||||
|
AppMsg.STYLE_ALERT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEncryptInterface.getSignatureKey() != 0
|
||||||
|
&& PassphraseCacheService.getCachedPassphrase(getActivity(), mEncryptInterface.getSignatureKey()) == null) {
|
||||||
|
showPassphraseDialog(toClipboard);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptStart(toClipboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encryptStart(final boolean toClipboard) {
|
||||||
|
// Send all information needed to service to edit key in other thread
|
||||||
|
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
|
||||||
|
|
||||||
|
// fill values for this action
|
||||||
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
|
long encryptionKeyIds[] = null;
|
||||||
|
int compressionId = 0;
|
||||||
|
boolean signOnly = false;
|
||||||
|
long mSecretKeyIdToPass = 0;
|
||||||
|
|
||||||
|
if (mEncryptInterface.isModeSymmetric()) {
|
||||||
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
|
String passphrase = mEncryptInterface.getPassphrase();
|
||||||
|
if (passphrase.length() == 0) {
|
||||||
|
passphrase = null;
|
||||||
|
}
|
||||||
|
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase);
|
||||||
|
} else {
|
||||||
|
mSecretKeyIdToPass = mEncryptInterface.getSignatureKey();
|
||||||
|
encryptionKeyIds = mEncryptInterface.getEncryptionKeys();
|
||||||
|
signOnly = (mEncryptInterface.getEncryptionKeys() == null
|
||||||
|
|| mEncryptInterface.getEncryptionKeys().length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN);
|
||||||
|
|
||||||
|
// choose default settings, target and data bundle by target
|
||||||
|
compressionId = Preferences.getPreferences(getActivity()).getDefaultMessageCompression();
|
||||||
|
|
||||||
|
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
|
||||||
|
|
||||||
|
String message = mMessage.getText().toString();
|
||||||
|
if (signOnly) {
|
||||||
|
message = fixBadCharactersForGmail(message);
|
||||||
|
}
|
||||||
|
data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, message.getBytes());
|
||||||
|
|
||||||
|
data.putLong(KeychainIntentService.ENCRYPT_SECRET_KEY_ID, mSecretKeyIdToPass);
|
||||||
|
data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, true);
|
||||||
|
data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, encryptionKeyIds);
|
||||||
|
data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId);
|
||||||
|
// data.putBoolean(KeychainIntentService.ENCRYPT_GENERATE_SIGNATURE, mGenerateSignature);
|
||||||
|
data.putBoolean(KeychainIntentService.ENCRYPT_SIGN_ONLY, signOnly);
|
||||||
|
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
|
||||||
|
// Message is received after encrypting is done in KeychainIntentService
|
||||||
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
|
||||||
|
getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
// handle messages by standard KeychainIntentServiceHandler first
|
||||||
|
super.handleMessage(message);
|
||||||
|
|
||||||
|
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||||
|
// get returned data bundle
|
||||||
|
Bundle data = message.getData();
|
||||||
|
|
||||||
|
String output;
|
||||||
|
if (toClipboard) {
|
||||||
|
output = data.getString(KeychainIntentService.RESULT_ENCRYPTED_STRING);
|
||||||
|
Log.d(Constants.TAG, "output: " + output);
|
||||||
|
ClipboardReflection.copyToClipboard(getActivity(), output);
|
||||||
|
AppMsg.makeText(getActivity(),
|
||||||
|
R.string.encryption_to_clipboard_successful, AppMsg.STYLE_INFO)
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
output = data.getString(KeychainIntentService.RESULT_ENCRYPTED_STRING);
|
||||||
|
Log.d(Constants.TAG, "output: " + output);
|
||||||
|
|
||||||
|
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
|
||||||
|
// Type is set to text/plain so that encrypted messages can
|
||||||
|
// be sent with Whatsapp, Hangouts, SMS etc...
|
||||||
|
sendIntent.setType("text/plain");
|
||||||
|
|
||||||
|
sendIntent.putExtra(Intent.EXTRA_TEXT, output);
|
||||||
|
startActivity(Intent.createChooser(sendIntent,
|
||||||
|
getString(R.string.title_send_email)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(saveHandler);
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
|
||||||
|
|
||||||
|
// show progress dialog
|
||||||
|
saveHandler.showProgressDialog(getActivity());
|
||||||
|
|
||||||
|
// start service with intent
|
||||||
|
getActivity().startService(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows passphrase dialog to cache a new passphrase the user enters for using it later for
|
||||||
|
* encryption
|
||||||
|
*/
|
||||||
|
private void showPassphraseDialog(final boolean toClipboard) {
|
||||||
|
// Message is received after passphrase is cached
|
||||||
|
Handler returnHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||||
|
encryptStart(toClipboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
|
|
||||||
|
try {
|
||||||
|
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||||
|
getActivity(), messenger, mEncryptInterface.getSignatureKey());
|
||||||
|
|
||||||
|
passphraseDialog.show(getActivity().getSupportFragmentManager(), "passphraseDialog");
|
||||||
|
} catch (PgpGeneralException e) {
|
||||||
|
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
|
||||||
|
// send message to handler to start encryption directly
|
||||||
|
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
|
||||||
|
public class EncryptSymmetricFragment extends Fragment {
|
||||||
|
|
||||||
|
OnSymmetricKeySelection mPassphraseUpdateListener;
|
||||||
|
|
||||||
|
private EditText mPassphrase;
|
||||||
|
private EditText mPassphraseAgain;
|
||||||
|
|
||||||
|
// Container Activity must implement this interface
|
||||||
|
public interface OnSymmetricKeySelection {
|
||||||
|
public void onPassphraseUpdate(String passphrase);
|
||||||
|
|
||||||
|
public void onPassphraseAgainUpdate(String passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
try {
|
||||||
|
mPassphraseUpdateListener = (OnSymmetricKeySelection) activity;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException(activity.toString() + " must implement OnSymmetricKeySelection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflate the layout for this fragment
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false);
|
||||||
|
|
||||||
|
mPassphrase = (EditText) view.findViewById(R.id.passphrase);
|
||||||
|
mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain);
|
||||||
|
mPassphrase.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
mPassphraseUpdateListener.onPassphraseUpdate(s.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mPassphraseAgain.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
mPassphraseUpdateListener.onPassphraseAgainUpdate(s.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,7 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:id="@+id/linearLayout">
|
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/decrypt_file_filename"
|
android:id="@+id/decrypt_file_filename"
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
android:layout_gravity="right"
|
android:layout_gravity="right"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/label_sign_user_id"
|
android:text="Alice"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -44,7 +44,7 @@
|
|||||||
android:layout_gravity="right"
|
android:layout_gravity="right"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/label_sign_email"
|
android:text="alice@example.com"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -1,318 +1,37 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
android:id="@+id/content_frame"
|
||||||
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
|
android:layout_marginLeft="@dimen/drawer_content_padding"
|
||||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/content_frame"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginLeft="@dimen/drawer_content_padding"
|
android:orientation="vertical">
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
<android.support.v4.view.ViewPager
|
||||||
|
android:id="@+id/encrypt_pager_mode"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="150dp">
|
||||||
|
|
||||||
|
<android.support.v4.view.PagerTabStrip
|
||||||
|
android:id="@+id/encrypt_pager_tab_strip_mode"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_gravity="top"
|
||||||
android:paddingLeft="10dp"
|
android:background="@color/emphasis"
|
||||||
android:paddingRight="10dp">
|
android:textColor="#fff" />
|
||||||
|
</android.support.v4.view.ViewPager>
|
||||||
|
|
||||||
<LinearLayout
|
<android.support.v4.view.ViewPager
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/encrypt_pager_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:orientation="horizontal"
|
android:layout_height="match_parent">
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<ImageView
|
<android.support.v4.view.PagerTabStrip
|
||||||
android:id="@+id/modePrevious"
|
android:id="@+id/encrypt_pager_tab_strip_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_previous"/>
|
android:layout_gravity="top"
|
||||||
|
android:background="@color/emphasis"
|
||||||
|
android:textColor="#fff" />
|
||||||
|
</android.support.v4.view.ViewPager>
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:id="@+id/modeLabel"
|
|
||||||
style="@style/SectionHeader"
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center_horizontal|center_vertical"
|
|
||||||
android:text="@string/label_asymmetric"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/modeNext"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_next"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ViewFlipper
|
|
||||||
android:id="@+id/mode"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/modeAsymmetric"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/sign"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:text="@string/label_sign"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingRight="4dip">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/mainUserId"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/label_sign_user_id"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/mainUserIdRest"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/label_sign_email"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingBottom="3dip">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/label_selectPublicKeys"
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/label_select_public_keys"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
|
||||||
android:id="@+id/btn_selectEncryptKeys"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:text="@string/btn_select_encrypt_keys"
|
|
||||||
bootstrapbutton:bb_icon_left="fa-user"
|
|
||||||
bootstrapbutton:bb_size="default"
|
|
||||||
bootstrapbutton:bb_type="default"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TableLayout
|
|
||||||
android:id="@+id/modeSymmetric"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:stretchColumns="1">
|
|
||||||
|
|
||||||
<TableRow>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/label_passphrase"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:paddingRight="10dip"
|
|
||||||
android:text="@string/label_passphrase"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/passphrase"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="textPassword"/>
|
|
||||||
</TableRow>
|
|
||||||
|
|
||||||
<TableRow>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/label_passphraseAgain"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:paddingRight="10dip"
|
|
||||||
android:text="@string/label_passphrase_again"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/passphraseAgain"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="textPassword"/>
|
|
||||||
</TableRow>
|
|
||||||
</TableLayout>
|
|
||||||
</ViewFlipper>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/sourcePrevious"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_previous"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sourceLabel"
|
|
||||||
style="@style/SectionHeader"
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center_horizontal|center_vertical"
|
|
||||||
android:text="@string/label_message"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/sourceNext"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_next"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ViewFlipper
|
|
||||||
android:id="@+id/source"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dip"
|
|
||||||
android:layout_weight="1">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/sourceMessage"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/message"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="top"
|
|
||||||
android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
|
|
||||||
android:hint="@string/encrypt_content_edit_text_hint"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/sourceFile"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/filename"
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="top|left"
|
|
||||||
android:inputType="textMultiLine|textUri"
|
|
||||||
android:lines="4"
|
|
||||||
android:maxLines="10"
|
|
||||||
android:minLines="2"
|
|
||||||
android:scrollbars="vertical"/>
|
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
|
||||||
android:id="@+id/btn_browse"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="4dp"
|
|
||||||
bootstrapbutton:bb_icon_left="fa-folder-open"
|
|
||||||
bootstrapbutton:bb_roundedCorners="true"
|
|
||||||
bootstrapbutton:bb_size="default"
|
|
||||||
bootstrapbutton:bb_type="default"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
custom:foldedLabel="@string/btn_encryption_advanced_settings_show"
|
|
||||||
custom:unFoldedLabel="@string/btn_encryption_advanced_settings_hide"
|
|
||||||
custom:foldedIcon="fa-chevron-right"
|
|
||||||
custom:unFoldedIcon="fa-chevron-down">
|
|
||||||
|
|
||||||
<include layout="@layout/encrypt_content_adv_settings"/>
|
|
||||||
|
|
||||||
</org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ViewFlipper>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/SectionHeader"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:text="@string/section_encrypt_and_or_sign"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="4dp">
|
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
|
||||||
android:id="@+id/action_encrypt_share"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/btn_share"
|
|
||||||
bootstrapbutton:bb_icon_left="fa-share-square"
|
|
||||||
bootstrapbutton:bb_type="info"/>
|
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
|
||||||
android:id="@+id/action_encrypt_clipboard"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/btn_clipboard"
|
|
||||||
bootstrapbutton:bb_icon_left="fa-clipboard"
|
|
||||||
bootstrapbutton:bb_type="info"/>
|
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
|
||||||
android:id="@+id/action_encrypt_file"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/btn_encrypt_file"
|
|
||||||
bootstrapbutton:bb_icon_left="fa-lock"
|
|
||||||
bootstrapbutton:bb_type="info"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
@ -59,7 +59,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/section_encrypt_and_or_sign"
|
android:text="@string/section_encrypt_and_or_sign"
|
||||||
android:layout_above="@+id/decrypt_file_action_decrypt"
|
android:layout_above="@+id/action_encrypt_file"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentStart="true" />
|
android:layout_alignParentStart="true" />
|
||||||
|
|
||||||
@ -68,10 +68,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/btn_encrypt_file"
|
android:text="@string/btn_encrypt_file"
|
||||||
bootstrapbutton:bb_icon_left="fa-lock"
|
bootstrapbutton:bb_icon_left="fa-lock"
|
||||||
bootstrapbutton:bb_type="info" />
|
bootstrapbutton:bb_type="info"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -135,8 +135,6 @@
|
|||||||
<string name="label_name">Name</string>
|
<string name="label_name">Name</string>
|
||||||
<string name="label_comment">Comment</string>
|
<string name="label_comment">Comment</string>
|
||||||
<string name="label_email">Email</string>
|
<string name="label_email">Email</string>
|
||||||
<string name="label_sign_user_id">Sign User Id</string>
|
|
||||||
<string name="label_sign_email">Sign email</string>
|
|
||||||
<string name="label_send_key">Upload key to selected keyserver after certification</string>
|
<string name="label_send_key">Upload key to selected keyserver after certification</string>
|
||||||
<string name="label_fingerprint">Fingerprint</string>
|
<string name="label_fingerprint">Fingerprint</string>
|
||||||
<string name="select_keys_button_default">Select</string>
|
<string name="select_keys_button_default">Select</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user