Encrypt/Decrypt UI work

This commit is contained in:
mar-v-in 2014-07-02 00:34:21 +02:00
parent 3564773410
commit 93eae114ea
12 changed files with 214 additions and 150 deletions

View File

@ -62,7 +62,7 @@ public class CachedPublicKeyRing extends KeyRing {
public String getPrimaryUserId() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.USER_ID,
ProviderHelper.FIELD_TYPE_STRING);
return (String) data;
} catch(ProviderHelper.NotFoundException e) {
@ -73,7 +73,7 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean isRevoked() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.IS_REVOKED,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@ -84,7 +84,7 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean canCertify() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.CAN_CERTIFY,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@ -106,7 +106,7 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean hasEncrypt() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.HAS_ENCRYPT,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@ -128,7 +128,7 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean hasSign() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.HAS_SIGN,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@ -139,7 +139,7 @@ public class CachedPublicKeyRing extends KeyRing {
public int getVerified() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.VERIFIED,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Integer) data;
} catch(ProviderHelper.NotFoundException e) {
@ -150,7 +150,7 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean hasAnySecret() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.HAS_ANY_SECRET,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {

View File

@ -29,7 +29,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.ImageButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@ -52,7 +51,6 @@ public class DecryptFileFragment extends DecryptFragment {
// view
private TextView mFilename;
private CheckBox mDeleteAfter;
private ImageButton mBrowse;
private View mDecryptButton;
// model
@ -67,10 +65,9 @@ public class DecryptFileFragment extends DecryptFragment {
View view = inflater.inflate(R.layout.decrypt_file_fragment, container, false);
mFilename = (TextView) view.findViewById(R.id.decrypt_file_filename);
mBrowse = (ImageButton) view.findViewById(R.id.decrypt_file_browse);
mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption);
mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt);
mBrowse.setOnClickListener(new View.OnClickListener() {
view.findViewById(R.id.decrypt_file_browse).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Constants.KITKAT) {
FileHelper.openDocument(DecryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);

View File

@ -70,6 +70,7 @@ public class EncryptActivity extends DrawerActivity implements
// model used by message and file fragments
private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none;
private String mPassphrase;
private String mPassphraseAgain;
@ -84,6 +85,11 @@ public class EncryptActivity extends DrawerActivity implements
mEncryptionKeyIds = encryptionKeyIds;
}
@Override
public void onEncryptionUserSelected(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds;
}
@Override
public void onPassphraseUpdate(String passphrase) {
mPassphrase = passphrase;
@ -109,6 +115,11 @@ public class EncryptActivity extends DrawerActivity implements
return mEncryptionKeyIds;
}
@Override
public String[] getEncryptionUsers() {
return mEncryptionUserIds;
}
@Override
public String getPassphrase() {
return mPassphrase;

View File

@ -23,6 +23,7 @@ public interface EncryptActivityInterface {
public long getSignatureKey();
public long[] getEncryptionKeys();
public String[] getEncryptionUsers();
public String getPassphrase();
public String getPassphraseAgain();

View File

@ -59,12 +59,15 @@ public class EncryptAsymmetricFragment extends Fragment {
// model
private long mSecretKeyId = Constants.key.none;
private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null;
// Container Activity must implement this interface
public interface OnAsymmetricKeySelection {
public void onSigningKeySelected(long signingKeyId);
public void onEncryptionKeysSelected(long[] encryptionKeyIds);
public void onEncryptionUserSelected(String[] encryptionUserIds);
}
@Override
@ -91,6 +94,13 @@ public class EncryptAsymmetricFragment extends Fragment {
updateView();
}
private void setEncryptionUserIds(String[] encryptionUserIds) {
mEncryptionUserIds = encryptionUserIds;
// update key selection in EncryptActivity
mKeySelectionListener.onEncryptionUserSelected(encryptionUserIds);
updateView();
}
/**
* Inflate the layout for this fragment
*/
@ -159,12 +169,14 @@ public class EncryptAsymmetricFragment extends Fragment {
if (preselectedEncryptionKeyIds != null) {
Vector<Long> goodIds = new Vector<Long>();
for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
Vector<String> goodUserIds = new Vector<String>();
for (long preselectedId : preselectedEncryptionKeyIds) {
try {
long id = providerHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
preselectedEncryptionKeyIds[i])
).getMasterKeyId();
CachedPublicKeyRing ring = providerHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId));
long id = ring.getMasterKeyId();
ring.getSplitPrimaryUserId();
goodUserIds.add(ring.getPrimaryUserId());
goodIds.add(id);
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
@ -176,6 +188,7 @@ public class EncryptAsymmetricFragment extends Fragment {
keyIds[i] = goodIds.get(i);
}
setEncryptionKeyIds(keyIds);
setEncryptionUserIds(goodUserIds.toArray(new String[goodUserIds.size()]));
}
}
}
@ -249,6 +262,7 @@ public class EncryptAsymmetricFragment extends Fragment {
Bundle bundle = data.getExtras();
setEncryptionKeyIds(bundle
.getLongArray(SelectPublicKeyActivity.RESULT_EXTRA_MASTER_KEY_IDS));
setEncryptionUserIds(bundle.getStringArray(SelectPublicKeyActivity.RESULT_EXTRA_USER_IDS));
}
break;
}

View File

@ -33,12 +33,13 @@ import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.ImageButton;
import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
public class EncryptFileFragment extends Fragment {
public static final String ARG_URI = "uri";
@ -65,8 +68,7 @@ public class EncryptFileFragment extends Fragment {
private Spinner mFileCompression = null;
private TextView mFilename = null;
private CheckBox mDeleteAfter = null;
private CheckBox mShareAfter = null;
private ImageButton mBrowse = null;
private View mShareFile;
private View mEncryptFile;
// model
@ -94,13 +96,19 @@ public class EncryptFileFragment extends Fragment {
mEncryptFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptClicked();
encryptClicked(false);
}
});
mShareFile = view.findViewById(R.id.action_encrypt_share);
mShareFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptClicked(true);
}
});
mFilename = (TextView) view.findViewById(R.id.filename);
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
view.findViewById(R.id.btn_browse).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Constants.KITKAT) {
FileHelper.openDocument(EncryptFileFragment.this, "*/*", REQUEST_CODE_INPUT);
@ -136,7 +144,6 @@ public class EncryptFileFragment extends Fragment {
}
mDeleteAfter = (CheckBox) view.findViewById(R.id.deleteAfterEncryption);
mShareAfter = (CheckBox) view.findViewById(R.id.shareAfterEncryption);
mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmor);
mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmor());
@ -181,7 +188,7 @@ public class EncryptFileFragment extends Fragment {
}
}
private void encryptClicked() {
private void encryptClicked(boolean share) {
if (mInputUri == null) {
AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
return;
@ -236,10 +243,17 @@ public class EncryptFileFragment extends Fragment {
}
}
if (share) {
String targetName = FileHelper.getFilename(getActivity(), mInputUri) +
(mAsciiArmor.isChecked() ? ".asc" : ".gpg");
mOutputUri = TemporaryStorageProvider.createFile(getActivity(), targetName);
encryptStart(true);
} else {
showOutputFileDialog();
}
}
private void encryptStart() {
private void encryptStart(final boolean share) {
if (mInputUri == null || mOutputUri == null) {
throw new IllegalStateException("Something went terribly wrong if this happens!");
}
@ -300,11 +314,21 @@ public class EncryptFileFragment extends Fragment {
setInputUri(null);
}
if (mShareAfter.isChecked()) {
if (share) {
// Share encrypted file
Intent sendFileIntent = new Intent(Intent.ACTION_SEND);
sendFileIntent.setType("*/*");
sendFileIntent.putExtra(Intent.EXTRA_STREAM, mOutputUri);
if (!mEncryptInterface.isModeSymmetric() && mEncryptInterface.getEncryptionUsers() != null) {
Set<String> users = new HashSet<String>();
for (String user : mEncryptInterface.getEncryptionUsers()) {
String[] userId = KeyRing.splitUserId(user);
if (userId[1] != null) {
users.add(userId[1]);
}
}
sendFileIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
startActivity(Intent.createChooser(sendFileIntent,
getString(R.string.title_share_file)));
}
@ -336,7 +360,7 @@ public class EncryptFileFragment extends Fragment {
// This happens after output file was selected, so start our operation
if (resultCode == Activity.RESULT_OK && data != null) {
mOutputUri = data.getData();
encryptStart();
encryptStart(false);
}
return;
}

View File

@ -36,12 +36,17 @@ 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.KeyRing;
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;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class EncryptMessageFragment extends Fragment {
public static final String ARG_TEXT = "text";
@ -235,7 +240,17 @@ public class EncryptMessageFragment extends Fragment {
// Type is set to text/plain so that encrypted messages can
// be sent with Whatsapp, Hangouts, SMS etc...
sendIntent.setType("text/plain");
Log.d(Constants.TAG, "encrypt to:" + Arrays.toString(mEncryptInterface.getEncryptionUsers()));
if (!mEncryptInterface.isModeSymmetric() && mEncryptInterface.getEncryptionUsers() != null) {
Set<String> users = new HashSet<String>();
for (String user : mEncryptInterface.getEncryptionUsers()) {
String[] userId = KeyRing.splitUserId(user);
if (userId[1] != null) {
users.add(userId[1]);
}
}
sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()]));
}
sendIntent.putExtra(Intent.EXTRA_TEXT, output);
startActivity(Intent.createChooser(sendIntent,
getString(R.string.title_share_with)));

View File

@ -25,6 +25,7 @@ import android.provider.DocumentsContract;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
@ -53,8 +54,8 @@ public class DeleteFileDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Uri deleteUri = getArguments().containsKey(ARG_DELETE_URI) ? getArguments().<Uri>getParcelable(ARG_DELETE_URI) : null;
String deleteFilename = FileHelper.getFilename(getActivity(), deleteUri);
final Uri deleteUri = getArguments().getParcelable(ARG_DELETE_URI);
final String deleteFilename = FileHelper.getFilename(getActivity(), deleteUri);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
@ -69,53 +70,23 @@ public class DeleteFileDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int id) {
dismiss();
// We can not securely delete Uris, so just use usual delete on them
if (Constants.KITKAT) {
// We can not securely delete Documents, so just use usual delete on them
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) return;
}
// TODO!!! We can't delete files from Uri without trying to find it's real path
/*
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(activity, KeychainIntentService.class);
// fill values for this action
Bundle data = new Bundle();
intent.setAction(KeychainIntentService.ACTION_DELETE_FILE_SECURELY);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
getString(R.string.progress_deleting_securely),
ProgressDialog.STYLE_HORIZONTAL,
false,
null);
// Message is received after deleting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler =
new KeychainIntentServiceHandler(activity, deletingDialog) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
Toast.makeText(activity, R.string.file_delete_successful,
Toast.LENGTH_SHORT).show();
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
return;
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
return;
}
// show progress dialog
deletingDialog.show(activity.getSupportFragmentManager(), "deletingDialog");
Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, deleteFilename), Toast.LENGTH_SHORT).show();
// start service with intent
activity.startService(intent);
*/
// TODO: We can't delete that file...
// If possible we should find out if deletion is possible before even showing the option to do so.
}
});
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

View File

@ -27,31 +27,40 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_height="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
<EditText
android:id="@+id/decrypt_file_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" />
<ImageButton
android:id="@+id/decrypt_file_browse"
android:clickable="true"
style="@style/SelectableItem">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:src="@drawable/ic_action_collection"
android:background="@drawable/button_rounded"
android:layout_gravity="center_vertical"/>
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/label_file_colon"
android:gravity="center_vertical"/>
<TextView
android:id="@+id/decrypt_file_filename"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/filemanager_title_open"
android:drawableRight="@drawable/ic_action_collection"
android:drawablePadding="8dp"
android:gravity="center_vertical"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider"
android:layout_marginBottom="8dp"/>
<CheckBox
android:id="@+id/decrypt_file_delete_after_decryption"
android:layout_width="wrap_content"

View File

@ -35,19 +35,6 @@
android:text="@string/label_delete_after_encryption"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/shareAfterEncryption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/label_share_after_encryption"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -1,6 +1,5 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -9,38 +8,46 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_height="?android:attr/listPreferredItemHeight"
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" />
<ImageButton
android:id="@+id/btn_browse"
android:clickable="true"
style="@style/SelectableItem">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_action_collection"
android:background="@drawable/button_rounded"/>
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/label_file_colon"
android:gravity="center_vertical"/>
<TextView
android:id="@+id/filename"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/filemanager_title_open"
android:drawableRight="@drawable/ic_action_collection"
android:drawablePadding="8dp"
android:gravity="center_vertical"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider"
android:layout_marginBottom="8dp"/>
<org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -57,30 +64,56 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/action_encrypt_file"
<LinearLayout
android:id="@+id/action_encrypt_share"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:text="@string/btn_encrypt_file"
android:clickable="true"
style="@style/SelectableItem"
android:drawableRight="@drawable/ic_action_save"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="8dp" />
android:layout_marginBottom="8dp"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dip"
android:layout_height="match_parent"
android:text="@string/btn_encrypt_share_file"
android:layout_weight="1"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical"/>
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider"/>
<ImageButton
android:id="@+id/action_encrypt_file"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_save"
android:layout_gravity="center_vertical"
style="@style/SelectableItem"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider"
android:layout_above="@+id/action_encrypt_file" />
android:layout_above="@+id/action_encrypt_share"/>
</RelativeLayout>
</LinearLayout>

View File

@ -55,6 +55,7 @@
<string name="btn_decrypt_verify_message">Decrypt and verify message</string>
<string name="btn_decrypt_verify_clipboard">From Clipboard</string>
<string name="btn_encrypt_file">Encrypt and save file</string>
<string name="btn_encrypt_share_file">Encrypt and share file</string>
<string name="btn_save">Save</string>
<string name="btn_do_not_save">Cancel</string>
<string name="btn_delete">Delete</string>
@ -105,6 +106,7 @@
<string name="label_sign">Sign</string>
<string name="label_message">Message</string>
<string name="label_file">File</string>
<string name="label_file_colon">File:</string>
<string name="label_no_passphrase">No Passphrase</string>
<string name="label_passphrase">Passphrase</string>
<string name="label_passphrase_again">Again</string>