working DisplayTextActivity, more input support in DecryptActivity
This commit is contained in:
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
@@ -31,6 +32,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class PgpHelper {
|
public class PgpHelper {
|
||||||
@@ -52,9 +54,6 @@ public class PgpHelper {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* TODO: Does this really help on flash storage?
|
* TODO: Does this really help on flash storage?
|
||||||
*
|
*
|
||||||
* @param context
|
|
||||||
* @param progressable
|
|
||||||
* @param file
|
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static void deleteFileSecurely(Context context, Progressable progressable, File file)
|
public static void deleteFileSecurely(Context context, Progressable progressable, File file)
|
||||||
@@ -78,4 +77,72 @@ public class PgpHelper {
|
|||||||
raf.close();
|
raf.close();
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail
|
||||||
|
*/
|
||||||
|
public static String fixPgpMessage(String message) {
|
||||||
|
// windows newline -> unix newline
|
||||||
|
message = message.replaceAll("\r\n", "\n");
|
||||||
|
// Mac OS before X newline -> unix newline
|
||||||
|
message = message.replaceAll("\r", "\n");
|
||||||
|
|
||||||
|
// remove whitespaces before newline
|
||||||
|
message = message.replaceAll(" +\n", "\n");
|
||||||
|
// only two consecutive newlines are allowed
|
||||||
|
message = message.replaceAll("\n\n+", "\n\n");
|
||||||
|
|
||||||
|
// replace non breakable spaces
|
||||||
|
message = message.replaceAll("\\xa0", " ");
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixing broken PGP SIGNED MESSAGE Strings coming from GMail/AOSP Mail
|
||||||
|
*/
|
||||||
|
public static String fixPgpCleartextSignature(CharSequence input) {
|
||||||
|
if (!TextUtils.isEmpty(input)) {
|
||||||
|
String text = input.toString();
|
||||||
|
|
||||||
|
// windows newline -> unix newline
|
||||||
|
text = text.replaceAll("\r\n", "\n");
|
||||||
|
// Mac OS before X newline -> unix newline
|
||||||
|
text = text.replaceAll("\r", "\n");
|
||||||
|
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPgpContent(CharSequence input) {
|
||||||
|
// only decrypt if clipboard content is available and a pgp message or cleartext signature
|
||||||
|
if (!TextUtils.isEmpty(input)) {
|
||||||
|
Log.dEscaped(Constants.TAG, "input: " + input);
|
||||||
|
|
||||||
|
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String text = matcher.group(1);
|
||||||
|
text = fixPgpMessage(text);
|
||||||
|
|
||||||
|
Log.dEscaped(Constants.TAG, "input fixed: " + text);
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(input);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String text = matcher.group(1);
|
||||||
|
text = fixPgpCleartextSignature(text);
|
||||||
|
|
||||||
|
Log.dEscaped(Constants.TAG, "input fixed: " + text);
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
|
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
|
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
|
|
||||||
@@ -42,7 +44,8 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
/* Intents */
|
/* Intents */
|
||||||
public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA;
|
public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA;
|
||||||
// TODO handle this intent
|
// TODO handle this intent
|
||||||
public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT;
|
// public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT;
|
||||||
|
public static final String ACTION_DECRYPT_FROM_CLIPBOARD = Constants.INTENT_PREFIX + "DECRYPT_DATA_CLIPBOARD";
|
||||||
|
|
||||||
// intern
|
// intern
|
||||||
public static final String ACTION_DECRYPT_DATA_OPEN = Constants.INTENT_PREFIX + "DECRYPT_DATA_OPEN";
|
public static final String ACTION_DECRYPT_DATA_OPEN = Constants.INTENT_PREFIX + "DECRYPT_DATA_OPEN";
|
||||||
@@ -118,6 +121,17 @@ public class DecryptActivity extends BaseActivity {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ACTION_DECRYPT_FROM_CLIPBOARD: {
|
||||||
|
action = ACTION_DECRYPT_DATA;
|
||||||
|
|
||||||
|
CharSequence clipboardText = ClipboardReflection.getClipboardText(this);
|
||||||
|
String text = PgpHelper.getPgpContent(clipboardText);
|
||||||
|
Uri uri = readToTempFile(text);
|
||||||
|
uris.add(uri);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Intent.ACTION_VIEW:
|
case Intent.ACTION_VIEW:
|
||||||
// Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
|
// Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
|
||||||
action = ACTION_DECRYPT_DATA;
|
action = ACTION_DECRYPT_DATA;
|
||||||
|
|||||||
@@ -61,9 +61,6 @@ public class DecryptFilesInputFragment extends Fragment {
|
|||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.decrypt_files_input_fragment, container, false);
|
View view = inflater.inflate(R.layout.decrypt_files_input_fragment, container, false);
|
||||||
|
|
||||||
// hide result view for this fragment
|
|
||||||
getActivity().findViewById(R.id.result_main_layout).setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mFilename = (TextView) view.findViewById(R.id.decrypt_files_filename);
|
mFilename = (TextView) view.findViewById(R.id.decrypt_files_filename);
|
||||||
mDecryptButton = view.findViewById(R.id.decrypt_files_action_decrypt);
|
mDecryptButton = view.findViewById(R.id.decrypt_files_action_decrypt);
|
||||||
view.findViewById(R.id.decrypt_files_browse).setOnClickListener(new View.OnClickListener() {
|
view.findViewById(R.id.decrypt_files_browse).setOnClickListener(new View.OnClickListener() {
|
||||||
|
|||||||
@@ -25,15 +25,18 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
@@ -43,24 +46,19 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.KeychainService;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
|
|
||||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
public abstract class DecryptFragment
|
public abstract class DecryptFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
extends CachingCryptoOperationFragment<PgpDecryptVerifyInputParcel, DecryptVerifyResult>
|
|
||||||
implements LoaderManager.LoaderCallbacks<Cursor> {
|
|
||||||
|
|
||||||
public static final int LOADER_ID_UNIFIED = 0;
|
public static final int LOADER_ID_UNIFIED = 0;
|
||||||
public static final String ARG_DECRYPT_VERIFY_RESULT = "decrypt_verify_result";
|
public static final String ARG_DECRYPT_VERIFY_RESULT = "decrypt_verify_result";
|
||||||
@@ -75,11 +73,9 @@ public abstract class DecryptFragment
|
|||||||
protected TextView mSignatureEmail;
|
protected TextView mSignatureEmail;
|
||||||
protected TextView mSignatureAction;
|
protected TextView mSignatureAction;
|
||||||
|
|
||||||
private LinearLayout mContentLayout;
|
|
||||||
private LinearLayout mErrorOverlayLayout;
|
|
||||||
|
|
||||||
private OpenPgpSignatureResult mSignatureResult;
|
private OpenPgpSignatureResult mSignatureResult;
|
||||||
private DecryptVerifyResult mDecryptVerifyResult;
|
private DecryptVerifyResult mDecryptVerifyResult;
|
||||||
|
private ViewAnimator mOverlayAnimator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
@@ -98,18 +94,23 @@ public abstract class DecryptFragment
|
|||||||
mSignatureAction = (TextView) getActivity().findViewById(R.id.result_signature_action);
|
mSignatureAction = (TextView) getActivity().findViewById(R.id.result_signature_action);
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
mContentLayout = (LinearLayout) view.findViewById(R.id.decrypt_content);
|
mOverlayAnimator = (ViewAnimator) view;
|
||||||
mErrorOverlayLayout = (LinearLayout) view.findViewById(R.id.decrypt_error_overlay);
|
|
||||||
Button vErrorOverlayButton = (Button) view.findViewById(R.id.decrypt_error_overlay_button);
|
Button vErrorOverlayButton = (Button) view.findViewById(R.id.decrypt_error_overlay_button);
|
||||||
vErrorOverlayButton.setOnClickListener(new View.OnClickListener() {
|
vErrorOverlayButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
mOverlayAnimator.setDisplayedChild(0);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showErrorOverlay(boolean overlay) {
|
||||||
|
int child = overlay ? 1 : 0;
|
||||||
|
if (mOverlayAnimator.getDisplayedChild() != child) {
|
||||||
|
mOverlayAnimator.setDisplayedChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
@@ -205,9 +206,6 @@ public abstract class DecryptFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return returns false if signature is invalid, key is revoked or expired.
|
|
||||||
*/
|
|
||||||
protected void loadVerifyResult(DecryptVerifyResult decryptVerifyResult) {
|
protected void loadVerifyResult(DecryptVerifyResult decryptVerifyResult) {
|
||||||
|
|
||||||
mDecryptVerifyResult = decryptVerifyResult;
|
mDecryptVerifyResult = decryptVerifyResult;
|
||||||
@@ -227,8 +225,7 @@ public abstract class DecryptFragment
|
|||||||
|
|
||||||
getLoaderManager().destroyLoader(LOADER_ID_UNIFIED);
|
getLoaderManager().destroyLoader(LOADER_ID_UNIFIED);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
|
|
||||||
@@ -330,10 +327,7 @@ public abstract class DecryptFragment
|
|||||||
setSignatureLayoutVisibility(View.VISIBLE);
|
setSignatureLayoutVisibility(View.VISIBLE);
|
||||||
setShowAction(signatureKeyId);
|
setShowAction(signatureKeyId);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.VISIBLE);
|
onVerifyLoaded(true);
|
||||||
mContentLayout.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
onVerifyLoaded(false);
|
|
||||||
|
|
||||||
} else if (isExpired) {
|
} else if (isExpired) {
|
||||||
mSignatureText.setText(R.string.decrypt_result_signature_expired_key);
|
mSignatureText.setText(R.string.decrypt_result_signature_expired_key);
|
||||||
@@ -342,8 +336,7 @@ public abstract class DecryptFragment
|
|||||||
setSignatureLayoutVisibility(View.VISIBLE);
|
setSignatureLayoutVisibility(View.VISIBLE);
|
||||||
setShowAction(signatureKeyId);
|
setShowAction(signatureKeyId);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
|
|
||||||
@@ -355,8 +348,7 @@ public abstract class DecryptFragment
|
|||||||
setSignatureLayoutVisibility(View.VISIBLE);
|
setSignatureLayoutVisibility(View.VISIBLE);
|
||||||
setShowAction(signatureKeyId);
|
setShowAction(signatureKeyId);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
|
|
||||||
@@ -367,8 +359,7 @@ public abstract class DecryptFragment
|
|||||||
setSignatureLayoutVisibility(View.VISIBLE);
|
setSignatureLayoutVisibility(View.VISIBLE);
|
||||||
setShowAction(signatureKeyId);
|
setShowAction(signatureKeyId);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
|
|
||||||
@@ -379,8 +370,7 @@ public abstract class DecryptFragment
|
|||||||
setSignatureLayoutVisibility(View.VISIBLE);
|
setSignatureLayoutVisibility(View.VISIBLE);
|
||||||
setShowAction(signatureKeyId);
|
setShowAction(signatureKeyId);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
}
|
}
|
||||||
@@ -438,8 +428,7 @@ public abstract class DecryptFragment
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.GONE);
|
showErrorOverlay(false);
|
||||||
mContentLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
onVerifyLoaded(true);
|
onVerifyLoaded(true);
|
||||||
|
|
||||||
@@ -452,8 +441,7 @@ public abstract class DecryptFragment
|
|||||||
|
|
||||||
setSignatureLayoutVisibility(View.GONE);
|
setSignatureLayoutVisibility(View.GONE);
|
||||||
|
|
||||||
mErrorOverlayLayout.setVisibility(View.VISIBLE);
|
showErrorOverlay(true);
|
||||||
mContentLayout.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
onVerifyLoaded(false);
|
onVerifyLoaded(false);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -18,7 +18,13 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -262,7 +268,7 @@ public class DecryptListFragment
|
|||||||
cryptoOperation();
|
cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processResult(final Uri uri, DecryptVerifyResult result) {
|
private void processResult(final Uri uri, final DecryptVerifyResult result) {
|
||||||
|
|
||||||
Drawable icon = null;
|
Drawable icon = null;
|
||||||
OnClickListener onFileClick = null, onKeyClick = null;
|
OnClickListener onFileClick = null, onKeyClick = null;
|
||||||
@@ -301,9 +307,59 @@ public class DecryptListFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
Uri outputUri = mOutputUris.get(uri);
|
Uri outputUri = mOutputUris.get(uri);
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
intent.setDataAndType(outputUri, metadata.getMimeType());
|
if ("text/plain".equals(metadata.getMimeType())) {
|
||||||
activity.startActivity(intent);
|
|
||||||
|
Intent intent = new Intent(activity, DisplayTextActivity.class);
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
intent.putExtra(DisplayTextActivity.EXTRA_METADATA, result);
|
||||||
|
intent.setDataAndType(outputUri, "text/plain");
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
byte[] decryptedMessage;
|
||||||
|
{
|
||||||
|
InputStream in = activity.getContentResolver().openInputStream(outputUri);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
int read;
|
||||||
|
while ( (read = in.read(buf)) > 0) {
|
||||||
|
out.write(buf, 0, read);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
decryptedMessage = out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
String plaintext;
|
||||||
|
if (result.getCharset() != null) {
|
||||||
|
try {
|
||||||
|
plaintext = new String(decryptedMessage, result.getCharset());
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// if we can't decode properly, just fall back to utf-8
|
||||||
|
plaintext = new String(decryptedMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plaintext = new String(decryptedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, plaintext);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Notify.create(activity, "error", Style.ERROR).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.startActivity(intent);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Intent intent = new Intent(activity, DisplayTextActivity.class);
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
intent.putExtra(DisplayTextActivity.EXTRA_METADATA, result);
|
||||||
|
intent.setDataAndType(outputUri, metadata.getMimeType());
|
||||||
|
activity.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
|
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
@@ -43,11 +44,7 @@ public class DisplayTextActivity extends BaseActivity {
|
|||||||
// TODO make this only display text (maybe we need only the fragment?)
|
// TODO make this only display text (maybe we need only the fragment?)
|
||||||
|
|
||||||
/* Intents */
|
/* Intents */
|
||||||
public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT;
|
public static final String EXTRA_METADATA = OpenKeychainIntents.DECRYPT_EXTRA_METADATA;
|
||||||
public static final String EXTRA_TEXT = OpenKeychainIntents.DECRYPT_EXTRA_TEXT;
|
|
||||||
|
|
||||||
// intern
|
|
||||||
public static final String ACTION_DECRYPT_FROM_CLIPBOARD = Constants.INTENT_PREFIX + "DECRYPT_TEXT_FROM_CLIPBOARD";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -70,73 +67,6 @@ public class DisplayTextActivity extends BaseActivity {
|
|||||||
setContentView(R.layout.decrypt_text_activity);
|
setContentView(R.layout.decrypt_text_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail
|
|
||||||
*/
|
|
||||||
private String fixPgpMessage(String message) {
|
|
||||||
// windows newline -> unix newline
|
|
||||||
message = message.replaceAll("\r\n", "\n");
|
|
||||||
// Mac OS before X newline -> unix newline
|
|
||||||
message = message.replaceAll("\r", "\n");
|
|
||||||
|
|
||||||
// remove whitespaces before newline
|
|
||||||
message = message.replaceAll(" +\n", "\n");
|
|
||||||
// only two consecutive newlines are allowed
|
|
||||||
message = message.replaceAll("\n\n+", "\n\n");
|
|
||||||
|
|
||||||
// replace non breakable spaces
|
|
||||||
message = message.replaceAll("\\xa0", " ");
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixing broken PGP SIGNED MESSAGE Strings coming from GMail/AOSP Mail
|
|
||||||
*/
|
|
||||||
private String fixPgpCleartextSignature(CharSequence input) {
|
|
||||||
if (!TextUtils.isEmpty(input)) {
|
|
||||||
String text = input.toString();
|
|
||||||
|
|
||||||
// windows newline -> unix newline
|
|
||||||
text = text.replaceAll("\r\n", "\n");
|
|
||||||
// Mac OS before X newline -> unix newline
|
|
||||||
text = text.replaceAll("\r", "\n");
|
|
||||||
|
|
||||||
return text;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPgpContent(CharSequence input) {
|
|
||||||
// only decrypt if clipboard content is available and a pgp message or cleartext signature
|
|
||||||
if (!TextUtils.isEmpty(input)) {
|
|
||||||
Log.dEscaped(Constants.TAG, "input: " + input);
|
|
||||||
|
|
||||||
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
String text = matcher.group(1);
|
|
||||||
text = fixPgpMessage(text);
|
|
||||||
|
|
||||||
Log.dEscaped(Constants.TAG, "input fixed: " + text);
|
|
||||||
return text;
|
|
||||||
} else {
|
|
||||||
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(input);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
String text = matcher.group(1);
|
|
||||||
text = fixPgpCleartextSignature(text);
|
|
||||||
|
|
||||||
Log.dEscaped(Constants.TAG, "input fixed: " + text);
|
|
||||||
return text;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all actions with this intent
|
* Handles all actions with this intent
|
||||||
*/
|
*/
|
||||||
@@ -153,53 +83,15 @@ public class DisplayTextActivity extends BaseActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Intent.ACTION_SEND.equals(action) && type != null) {
|
Log.d(Constants.TAG, "ACTION_DECRYPT_TEXT");
|
||||||
Log.d(Constants.TAG, "ACTION_SEND");
|
|
||||||
Log.logDebugBundle(extras, "SEND extras");
|
|
||||||
|
|
||||||
// When sending to Keychain Decrypt via share menu
|
DecryptVerifyResult result = extras.getParcelable(EXTRA_METADATA);
|
||||||
if ("text/plain".equals(type)) {
|
String plaintext = extras.getString(Intent.EXTRA_TEXT);
|
||||||
String sharedText = extras.getString(Intent.EXTRA_TEXT);
|
|
||||||
sharedText = getPgpContent(sharedText);
|
|
||||||
|
|
||||||
if (sharedText != null) {
|
if (plaintext != null) {
|
||||||
loadFragment(sharedText);
|
loadFragment(plaintext, result);
|
||||||
} else {
|
} else {
|
||||||
Log.e(Constants.TAG, "EXTRA_TEXT does not contain PGP content!");
|
Log.e(Constants.TAG, "EXTRA_TEXT does not contain PGP content!");
|
||||||
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(Constants.TAG, "ACTION_SEND received non-plaintext, this should not happen in this activity!");
|
|
||||||
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else if (ACTION_DECRYPT_TEXT.equals(action)) {
|
|
||||||
Log.d(Constants.TAG, "ACTION_DECRYPT_TEXT");
|
|
||||||
|
|
||||||
String extraText = extras.getString(EXTRA_TEXT);
|
|
||||||
extraText = getPgpContent(extraText);
|
|
||||||
|
|
||||||
if (extraText != null) {
|
|
||||||
loadFragment(extraText);
|
|
||||||
} else {
|
|
||||||
Log.e(Constants.TAG, "EXTRA_TEXT does not contain PGP content!");
|
|
||||||
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) {
|
|
||||||
Log.d(Constants.TAG, "ACTION_DECRYPT_FROM_CLIPBOARD");
|
|
||||||
|
|
||||||
CharSequence clipboardText = ClipboardReflection.getClipboardText(this);
|
|
||||||
String text = getPgpContent(clipboardText);
|
|
||||||
|
|
||||||
if (text != null) {
|
|
||||||
loadFragment(text);
|
|
||||||
} else {
|
|
||||||
returnInvalidResult();
|
|
||||||
}
|
|
||||||
} else if (ACTION_DECRYPT_TEXT.equals(action)) {
|
|
||||||
Log.e(Constants.TAG, "Include the extra 'text' in your Intent!");
|
|
||||||
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
@@ -214,9 +106,9 @@ public class DisplayTextActivity extends BaseActivity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFragment(String ciphertext) {
|
private void loadFragment(String plaintext, DecryptVerifyResult result) {
|
||||||
// Create an instance of the fragment
|
// Create an instance of the fragment
|
||||||
Fragment frag = DisplayTextFragment.newInstance(ciphertext);
|
Fragment frag = DisplayTextFragment.newInstance(plaintext, result);
|
||||||
|
|
||||||
// Add the fragment to the 'fragment_container' FrameLayout
|
// Add the fragment to the 'fragment_container' FrameLayout
|
||||||
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
||||||
|
|||||||
@@ -31,45 +31,32 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.util.ShareHelper;
|
import org.sufficientlysecure.keychain.util.ShareHelper;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
public class DisplayTextFragment extends DecryptFragment {
|
public class DisplayTextFragment extends DecryptFragment {
|
||||||
public static final String ARG_CIPHERTEXT = "ciphertext";
|
public static final String ARG_PLAINTEXT = "ciphertext";
|
||||||
public static final String ARG_SHOW_MENU = "show_menu";
|
public static final String ARG_SHOW_MENU = "show_menu";
|
||||||
|
|
||||||
// view
|
// view
|
||||||
private TextView mText;
|
private TextView mText;
|
||||||
|
|
||||||
// model
|
// model
|
||||||
private String mCiphertext;
|
|
||||||
private boolean mShowMenuOptions;
|
private boolean mShowMenuOptions;
|
||||||
|
private String mPlaintext;
|
||||||
|
|
||||||
public static DisplayTextFragment newInstance(String ciphertext) {
|
public static DisplayTextFragment newInstance(String plaintext, DecryptVerifyResult result) {
|
||||||
DisplayTextFragment frag = new DisplayTextFragment();
|
DisplayTextFragment frag = new DisplayTextFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_CIPHERTEXT, ciphertext);
|
args.putString(ARG_PLAINTEXT, plaintext);
|
||||||
|
args.putParcelable(ARG_DECRYPT_VERIFY_RESULT, result);
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Inflate the layout for this fragment
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false);
|
|
||||||
mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Intent Chooser but exclude decrypt activites
|
* Create Intent Chooser but exclude decrypt activites
|
||||||
*/
|
*/
|
||||||
@@ -79,7 +66,7 @@ public class DisplayTextFragment extends DecryptFragment {
|
|||||||
|
|
||||||
// we don't want to decrypt the decrypted, no inception ;)
|
// we don't want to decrypt the decrypted, no inception ;)
|
||||||
String[] blacklist = new String[]{
|
String[] blacklist = new String[]{
|
||||||
Constants.PACKAGE_NAME + ".ui.DecryptTextActivity",
|
Constants.PACKAGE_NAME + ".ui.DecryptActivity",
|
||||||
"org.thialfihar.android.apg.ui.DecryptActivity"
|
"org.thialfihar.android.apg.ui.DecryptActivity"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,13 +91,30 @@ public class DisplayTextFragment extends DecryptFragment {
|
|||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
|
Bundle args = getArguments();
|
||||||
mCiphertext = args.getString(ARG_CIPHERTEXT);
|
|
||||||
mShowMenuOptions = args.getBoolean(ARG_SHOW_MENU, false);
|
mShowMenuOptions = args.getBoolean(ARG_SHOW_MENU, false);
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
}
|
||||||
cryptoOperation();
|
|
||||||
}
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false);
|
||||||
|
mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
Bundle args = getArguments();
|
||||||
|
|
||||||
|
String plaintext = args.getString(ARG_PLAINTEXT);
|
||||||
|
DecryptVerifyResult result = args.getParcelable(ARG_DECRYPT_VERIFY_RESULT);
|
||||||
|
|
||||||
|
// display signature result in activity
|
||||||
|
mText.setText(plaintext);
|
||||||
|
loadVerifyResult(result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,12 +122,17 @@ public class DisplayTextFragment extends DecryptFragment {
|
|||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
outState.putString(ARG_CIPHERTEXT, mCiphertext);
|
|
||||||
outState.putBoolean(ARG_SHOW_MENU, mShowMenuOptions);
|
outState.putBoolean(ARG_SHOW_MENU, mShowMenuOptions);
|
||||||
// no need to save the decrypted text, it's in the textview
|
// no need to save the decrypted text, it's in the textview
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onVerifyLoaded(boolean hideErrorOverlay) {
|
||||||
|
mShowMenuOptions = hideErrorOverlay;
|
||||||
|
getActivity().supportInvalidateOptionsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
@@ -151,39 +160,4 @@ public class DisplayTextFragment extends DecryptFragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PgpDecryptVerifyInputParcel createOperationInput() {
|
|
||||||
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
|
|
||||||
input.setAllowSymmetricDecryption(true);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onVerifyLoaded(boolean hideErrorOverlay) {
|
|
||||||
mShowMenuOptions = hideErrorOverlay;
|
|
||||||
getActivity().supportInvalidateOptionsMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCryptoOperationSuccess(DecryptVerifyResult result) {
|
|
||||||
|
|
||||||
byte[] decryptedMessage = result.getOutputBytes();
|
|
||||||
String displayMessage;
|
|
||||||
if (result.getCharset() != null) {
|
|
||||||
try {
|
|
||||||
displayMessage = new String(decryptedMessage, result.getCharset());
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// if we can't decode properly, just fall back to utf-8
|
|
||||||
displayMessage = new String(decryptedMessage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
displayMessage = new String(decryptedMessage);
|
|
||||||
}
|
|
||||||
mText.setText(displayMessage);
|
|
||||||
|
|
||||||
// display signature result in activity
|
|
||||||
loadVerifyResult(result);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ public class EncryptDecryptOverviewFragment extends Fragment {
|
|||||||
mDecryptFromClipboard.setOnClickListener(new View.OnClickListener() {
|
mDecryptFromClipboard.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent clipboardDecrypt = new Intent(getActivity(), DisplayTextActivity.class);
|
Intent clipboardDecrypt = new Intent(getActivity(), DecryptActivity.class);
|
||||||
clipboardDecrypt.setAction(DisplayTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD);
|
clipboardDecrypt.setAction(DecryptActivity.ACTION_DECRYPT_FROM_CLIPBOARD);
|
||||||
startActivityForResult(clipboardDecrypt, 0);
|
startActivityForResult(clipboardDecrypt, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,14 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -59,13 +67,6 @@ import org.sufficientlysecure.keychain.util.Passphrase;
|
|||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
import org.sufficientlysecure.keychain.util.ShareHelper;
|
import org.sufficientlysecure.keychain.util.ShareHelper;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class EncryptFilesFragment
|
public class EncryptFilesFragment
|
||||||
extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> {
|
extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> {
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
@@ -63,4 +64,5 @@
|
|||||||
android:text="@string/decrypt_invalid_button"
|
android:text="@string/decrypt_invalid_button"
|
||||||
android:layout_gravity="center_horizontal" />
|
android:layout_gravity="center_horizontal" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
|
||||||
|
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||||
Reference in New Issue
Block a user