mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-30 12:32:17 -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.support.v4.view.PagerTabStrip;
|
||||
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 com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
import com.devspark.appmsg.AppMsg;
|
||||
|
||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@ -47,7 +37,6 @@ import java.util.regex.Matcher;
|
||||
public class DecryptActivity extends DrawerActivity {
|
||||
|
||||
/* Intents */
|
||||
// without permission
|
||||
public static final String ACTION_DECRYPT = Constants.INTENT_PREFIX + "DECRYPT";
|
||||
|
||||
/* 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_FILE = 1;
|
||||
|
||||
|
||||
private void initView() {
|
||||
// Pager
|
||||
mViewPager = (ViewPager) findViewById(R.id.decrypt_pager);
|
||||
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
|
||||
* 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 static final String ARG_FILENAME = "filename";
|
||||
|
||||
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||
|
||||
// view
|
||||
private EditText mFilename;
|
||||
private CheckBox mDeleteAfter;
|
||||
private BootstrapButton mBrowse;
|
||||
private BootstrapButton mDecryptButton;
|
||||
|
||||
|
||||
private String mInputFilename = null;
|
||||
private String mOutputFilename = null;
|
||||
|
||||
private FileDialogFragment mFileDialog;
|
||||
|
||||
private static final int RESULT_CODE_FILE = 0x00007003;
|
||||
|
||||
|
||||
/**
|
||||
* Inflate the layout for this fragment
|
||||
*/
|
||||
@ -72,14 +71,14 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
|
||||
mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename);
|
||||
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() {
|
||||
public void onClick(View v) {
|
||||
FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*",
|
||||
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() {
|
||||
@Override
|
||||
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);
|
||||
if (filename != null) {
|
||||
mFilename.setText(filename);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void guessOutputFilename() {
|
||||
@ -193,14 +197,12 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
|
||||
PgpDecryptVerifyResult decryptVerifyResult =
|
||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||
|
||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||
} else {
|
||||
|
||||
if (mDeleteAfter.isChecked()) {
|
||||
// Create and show dialog to delete original file
|
||||
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
|
||||
@ -208,13 +210,11 @@ public class DecryptFileFragment extends DecryptFragment {
|
||||
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
|
||||
}
|
||||
|
||||
|
||||
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||
|
||||
// display signature result in activity
|
||||
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
|
||||
* 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) {
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
* 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 mDecryptFromCLipboardButton;
|
||||
|
||||
|
||||
/**
|
||||
* Inflate the layout for this fragment
|
||||
*/
|
||||
@ -61,14 +60,12 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
mMessage = (EditText) view.findViewById(R.id.message);
|
||||
mDecryptButton = (BootstrapButton) view.findViewById(R.id.action_decrypt);
|
||||
mDecryptFromCLipboardButton = (BootstrapButton) view.findViewById(R.id.action_decrypt_from_clipboard);
|
||||
|
||||
mDecryptButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
decryptStart(null);
|
||||
}
|
||||
});
|
||||
|
||||
mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@ -93,6 +90,7 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
private void decryptFromClipboard() {
|
||||
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
|
||||
|
||||
// only decrypt if clipboard content is available and a pgp message or cleartext signature
|
||||
if (clipboardText != null) {
|
||||
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText);
|
||||
if (!matcher.matches()) {
|
||||
@ -146,14 +144,12 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
// get returned data bundle
|
||||
Bundle returnData = message.getData();
|
||||
|
||||
|
||||
PgpDecryptVerifyResult decryptVerifyResult =
|
||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||
|
||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||
} else {
|
||||
|
||||
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
||||
AppMsg.STYLE_INFO).show();
|
||||
|
||||
@ -162,13 +158,11 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
mMessage.setText(new String(decryptedMessage));
|
||||
mMessage.setHorizontallyScrolling(false);
|
||||
|
||||
|
||||
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||
|
||||
// display signature result in activity
|
||||
onSignatureResult(signatureResult);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -184,5 +178,4 @@ public class DecryptMessageFragment extends DecryptFragment {
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/linearLayout">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/decrypt_file_filename"
|
||||
|
@ -34,7 +34,7 @@
|
||||
android:layout_gravity="right"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_sign_user_id"
|
||||
android:text="Alice"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
@ -44,7 +44,7 @@
|
||||
android:layout_gravity="right"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_sign_email"
|
||||
android:text="alice@example.com"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -1,318 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_marginLeft="@dimen/drawer_content_padding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
android:orientation="vertical">
|
||||
|
||||
<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_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
android:layout_gravity="top"
|
||||
android:background="@color/emphasis"
|
||||
android:textColor="#fff" />
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
<LinearLayout
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/encrypt_pager_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v4.view.PagerTabStrip
|
||||
android:id="@+id/encrypt_pager_tab_strip_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/modePrevious"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_previous"/>
|
||||
|
||||
<TextView
|
||||
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>
|
||||
android:layout_gravity="top"
|
||||
android:background="@color/emphasis"
|
||||
android:textColor="#fff" />
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
</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_height="wrap_content"
|
||||
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_alignParentStart="true" />
|
||||
|
||||
@ -68,10 +68,12 @@
|
||||
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" />
|
||||
bootstrapbutton:bb_type="info"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
@ -135,8 +135,6 @@
|
||||
<string name="label_name">Name</string>
|
||||
<string name="label_comment">Comment</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_fingerprint">Fingerprint</string>
|
||||
<string name="select_keys_button_default">Select</string>
|
||||
|
Loading…
Reference in New Issue
Block a user