Merge pull request #1331 from open-keychain/v/eventbus

replace messenger hack with eventbus
This commit is contained in:
Vincent 2015-06-12 14:59:26 +02:00
commit d57324aa4b
34 changed files with 581 additions and 807 deletions

View File

@ -716,6 +716,9 @@
android:name=".remote.CryptoInputParcelCacheService" android:name=".remote.CryptoInputParcelCacheService"
android:exported="false" android:exported="false"
android:process=":remote_api" /> android:process=":remote_api" />
<service
android:name=".service.KeychainNewService"
android:exported="false" />
<service <service
android:name=".service.KeychainService" android:name=".service.KeychainService"
android:exported="false" /> android:exported="false" />

View File

@ -18,17 +18,20 @@
package org.sufficientlysecure.keychain.operations; package org.sufficientlysecure.keychain.operations;
import android.content.Context; import android.content.Context;
import android.os.Parcelable;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface; import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public abstract class BaseOperation implements PassphraseCacheInterface { public abstract class BaseOperation <T extends Parcelable> implements PassphraseCacheInterface {
final public Context mContext; final public Context mContext;
final public Progressable mProgressable; final public Progressable mProgressable;
@ -73,6 +76,10 @@ public abstract class BaseOperation implements PassphraseCacheInterface {
mCancelled = cancelled; mCancelled = cancelled;
} }
public OperationResult execute(T input, CryptoInputParcel cryptoInput) {
return null;
}
public void updateProgress(int message, int current, int total) { public void updateProgress(int message, int current, int total) {
if (mProgressable != null) { if (mProgressable != null) {
mProgressable.setProgress(message, current, total); mProgressable.setProgress(message, current, total);

View File

@ -64,7 +64,7 @@ public class CertifyOperation extends BaseOperation {
super(context, providerHelper, progressable, cancelled); super(context, providerHelper, progressable, cancelled);
} }
public CertifyResult certify(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput, String keyServerUri) { public CertifyResult execute(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
log.add(LogType.MSG_CRT, 0); log.add(LogType.MSG_CRT, 0);
@ -186,8 +186,8 @@ public class CertifyOperation extends BaseOperation {
HkpKeyserver keyServer = null; HkpKeyserver keyServer = null;
ImportExportOperation importExportOperation = null; ImportExportOperation importExportOperation = null;
if (keyServerUri != null) { if (parcel.keyServerUri != null) {
keyServer = new HkpKeyserver(keyServerUri); keyServer = new HkpKeyserver(parcel.keyServerUri);
importExportOperation = new ImportExportOperation(mContext, mProviderHelper, mProgressable); importExportOperation = new ImportExportOperation(mContext, mProviderHelper, mProgressable);
} }

View File

@ -37,7 +37,6 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -51,7 +50,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @see SaveKeyringParcel * @see SaveKeyringParcel
* *
*/ */
public class EditKeyOperation extends BaseOperation { public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
public EditKeyOperation(Context context, ProviderHelper providerHelper, public EditKeyOperation(Context context, ProviderHelper providerHelper,
Progressable progressable, AtomicBoolean cancelled) { Progressable progressable, AtomicBoolean cancelled) {

View File

@ -55,7 +55,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* a pending result, it will terminate. * a pending result, it will terminate.
* *
*/ */
public class SignEncryptOperation extends BaseOperation { public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
public SignEncryptOperation(Context context, ProviderHelper providerHelper, public SignEncryptOperation(Context context, ProviderHelper providerHelper,
Progressable progressable, AtomicBoolean cancelled) { Progressable progressable, AtomicBoolean cancelled) {

View File

@ -76,10 +76,7 @@ import java.security.SignatureException;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
/** public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel> {
* This class uses a Builder pattern!
*/
public class PgpDecryptVerify extends BaseOperation {
public PgpDecryptVerify(Context context, ProviderHelper providerHelper, Progressable progressable) { public PgpDecryptVerify(Context context, ProviderHelper providerHelper, Progressable progressable) {
super(context, providerHelper, progressable); super(context, providerHelper, progressable);

View File

@ -20,13 +20,8 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Map;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;

View File

@ -43,6 +43,8 @@ public class CertifyActionsParcel implements Parcelable {
public ArrayList<CertifyAction> mCertifyActions = new ArrayList<>(); public ArrayList<CertifyAction> mCertifyActions = new ArrayList<>();
public String keyServerUri;
public CertifyActionsParcel(long masterKeyId) { public CertifyActionsParcel(long masterKeyId) {
mMasterKeyId = masterKeyId; mMasterKeyId = masterKeyId;
mLevel = CertifyLevel.DEFAULT; mLevel = CertifyLevel.DEFAULT;

View File

@ -0,0 +1,188 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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.service;
import java.util.concurrent.atomic.AtomicBoolean;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.operations.BaseOperation;
import org.sufficientlysecure.keychain.operations.CertifyOperation;
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.util.Log;
/**
* This Service contains all important long lasting operations for OpenKeychain. It receives Intents with
* data from the activities or other apps, executes them, and stops itself after doing them.
*/
public class KeychainNewService extends Service implements Progressable {
// messenger for communication (hack)
public static final String EXTRA_MESSENGER = "messenger";
// extras for operation
public static final String EXTRA_OPERATION_INPUT = "op_input";
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// this attribute can possibly merged with the one above? not sure...
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
ThreadLocal<Messenger> mMessenger = new ThreadLocal<>();
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* This is run on the main thread, we need to spawn a runnable which runs on another thread for the actual operation
*/
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Runnable actionRunnable = new Runnable() {
@Override
public void run() {
// We have not been cancelled! (yet)
mActionCanceled.set(false);
Bundle extras = intent.getExtras();
// Set messenger for communication (for this particular thread)
mMessenger.set(extras.<Messenger>getParcelable(EXTRA_MESSENGER));
// Input
Parcelable inputParcel = extras.getParcelable(EXTRA_OPERATION_INPUT);
CryptoInputParcel cryptoInput = extras.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
BaseOperation op;
// just for brevity
KeychainNewService outerThis = KeychainNewService.this;
if (inputParcel instanceof SignEncryptParcel) {
op = new SignEncryptOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerify(outerThis, new ProviderHelper(outerThis), outerThis);
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else if (inputParcel instanceof CertifyAction) {
op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else {
return;
}
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
OperationResult result = op.execute(inputParcel, cryptoInput);
sendMessageToHandler(MessageStatus.OKAY, result);
}
};
Thread actionThread = new Thread(actionRunnable);
actionThread.start();
return START_NOT_STICKY;
}
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
Message msg = Message.obtain();
assert msg != null;
msg.arg1 = status.ordinal();
if (arg2 != null) {
msg.arg2 = arg2;
}
if (data != null) {
msg.setData(data);
}
try {
mMessenger.get().send(msg);
} catch (RemoteException e) {
Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
} catch (NullPointerException e) {
Log.w(Constants.TAG, "Messenger is null!", e);
}
}
private void sendMessageToHandler(MessageStatus status, OperationResult data) {
Bundle bundle = new Bundle();
bundle.putParcelable(OperationResult.EXTRA_RESULT, data);
sendMessageToHandler(status, null, bundle);
}
private void sendMessageToHandler(MessageStatus status) {
sendMessageToHandler(status, null, null);
}
/**
* Set progress of ProgressDialog by sending message to handler on UI thread
*/
@Override
public void setProgress(String message, int progress, int max) {
Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max="
+ max);
Bundle data = new Bundle();
if (message != null) {
data.putString(ServiceProgressHandler.DATA_MESSAGE, message);
}
data.putInt(ServiceProgressHandler.DATA_PROGRESS, progress);
data.putInt(ServiceProgressHandler.DATA_PROGRESS_MAX, max);
sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, null, data);
}
@Override
public void setProgress(int resourceId, int progress, int max) {
setProgress(getString(resourceId), progress, max);
}
@Override
public void setProgress(int progress, int max) {
setProgress(null, progress, max);
}
@Override
public void setPreventCancel() {
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
}
}

View File

@ -96,14 +96,9 @@ public class KeychainService extends Service implements Progressable {
public static final String EXTRA_DATA = "data"; public static final String EXTRA_DATA = "data";
/* possible actions */ /* possible actions */
public static final String ACTION_SIGN_ENCRYPT = Constants.INTENT_PREFIX + "SIGN_ENCRYPT";
public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY";
public static final String ACTION_VERIFY_KEYBASE_PROOF = Constants.INTENT_PREFIX + "VERIFY_KEYBASE_PROOF"; public static final String ACTION_VERIFY_KEYBASE_PROOF = Constants.INTENT_PREFIX + "VERIFY_KEYBASE_PROOF";
public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA";
public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING";
public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING"; public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING";
@ -113,8 +108,6 @@ public class KeychainService extends Service implements Progressable {
public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING"; public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING";
public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE"; public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE";
public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE"; public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
@ -123,14 +116,6 @@ public class KeychainService extends Service implements Progressable {
/* keys for data bundle */ /* keys for data bundle */
// encrypt
public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri";
public static final String ENCRYPT_DECRYPT_OUTPUT_URI = "output_uri";
public static final String SIGN_ENCRYPT_PARCEL = "sign_encrypt_parcel";
// decrypt/verify
public static final String DECRYPT_VERIFY_PARCEL = "decrypt_verify_parcel";
// keybase proof // keybase proof
public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint"; public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint";
public static final String KEYBASE_PROOF = "keybase_proof"; public static final String KEYBASE_PROOF = "keybase_proof";
@ -158,9 +143,6 @@ public class KeychainService extends Service implements Progressable {
// upload key // upload key
public static final String UPLOAD_KEY_SERVER = "upload_key_server"; public static final String UPLOAD_KEY_SERVER = "upload_key_server";
// certify key
public static final String CERTIFY_PARCEL = "certify_parcel";
// promote key // promote key
public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id"; public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id";
public static final String PROMOTE_CARD_AID = "promote_card_aid"; public static final String PROMOTE_CARD_AID = "promote_card_aid";
@ -232,23 +214,6 @@ public class KeychainService extends Service implements Progressable {
// executeServiceMethod action from extra bundle // executeServiceMethod action from extra bundle
switch (action) { switch (action) {
case ACTION_CERTIFY_KEYRING: {
// Input
CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL);
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
String keyServerUri = data.getString(UPLOAD_KEY_SERVER);
// Operation
CertifyOperation op = new CertifyOperation(mKeychainService, providerHelper, mKeychainService,
mActionCanceled);
CertifyResult result = op.certify(parcel, cryptoInput, keyServerUri);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
break;
}
case ACTION_CONSOLIDATE: { case ACTION_CONSOLIDATE: {
// Operation // Operation
@ -264,24 +229,6 @@ public class KeychainService extends Service implements Progressable {
break; break;
} }
case ACTION_DECRYPT_METADATA: {
// Input
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
PgpDecryptVerifyInputParcel input = data.getParcelable(DECRYPT_VERIFY_PARCEL);
// this action is here for compatibility only
input.setDecryptMetadataOnly(true);
// Operation
PgpDecryptVerify op = new PgpDecryptVerify(mKeychainService, providerHelper, mKeychainService);
DecryptVerifyResult decryptVerifyResult = op.execute(input, cryptoInput);
// Result
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
break;
}
case ACTION_VERIFY_KEYBASE_PROOF: { case ACTION_VERIFY_KEYBASE_PROOF: {
try { try {
@ -376,25 +323,6 @@ public class KeychainService extends Service implements Progressable {
break; break;
} }
case ACTION_DECRYPT_VERIFY: {
// Input
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
PgpDecryptVerifyInputParcel input = data.getParcelable(DECRYPT_VERIFY_PARCEL);
// for compatibility
// TODO merge with ACTION_DECRYPT_METADATA
input.setDecryptMetadataOnly(false);
// Operation
PgpDecryptVerify op = new PgpDecryptVerify(mKeychainService, providerHelper, mKeychainService);
DecryptVerifyResult decryptVerifyResult = op.execute(input, cryptoInput);
// Output
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
break;
}
case ACTION_DELETE: { case ACTION_DELETE: {
// Input // Input
@ -495,22 +423,6 @@ public class KeychainService extends Service implements Progressable {
break; break;
} }
case ACTION_SIGN_ENCRYPT: {
// Input
SignEncryptParcel inputParcel = data.getParcelable(SIGN_ENCRYPT_PARCEL);
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
SignEncryptOperation op = new SignEncryptOperation(
mKeychainService, providerHelper, mKeychainService, mActionCanceled);
SignEncryptResult result = op.execute(inputParcel, cryptoInput);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
break;
}
case ACTION_UPLOAD_KEYRING: { case ACTION_UPLOAD_KEYRING: {
try { try {

View File

@ -17,8 +17,7 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
import android.app.Activity; import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@ -27,7 +26,6 @@ import android.support.v4.app.FragmentManager;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@ -65,68 +63,58 @@ public class ServiceProgressHandler extends Handler {
public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url"; public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url";
public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label"; public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label";
Activity mActivity; FragmentActivity mActivity;
ProgressDialogFragment mProgressDialogFragment;
public ServiceProgressHandler(Activity activity) { public ServiceProgressHandler(FragmentActivity activity) {
this.mActivity = activity; mActivity = activity;
} }
public ServiceProgressHandler(Activity activity, ProgressDialogFragment progressDialogFragment) { public void showProgressDialog() {
this.mActivity = activity; showProgressDialog("", ProgressDialog.STYLE_SPINNER, false);
this.mProgressDialogFragment = progressDialogFragment;
} }
public ServiceProgressHandler(Activity activity, String progressDialogMessage, int progressDialogStyle) { public void showProgressDialog(
this(activity, progressDialogMessage, progressDialogStyle, false); String progressDialogMessage, int progressDialogStyle, boolean cancelable) {
}
public ServiceProgressHandler(Activity activity, final ProgressDialogFragment frag = ProgressDialogFragment.newInstance(
String progressDialogMessage,
int progressDialogStyle,
boolean cancelable) {
this.mActivity = activity;
this.mProgressDialogFragment = ProgressDialogFragment.newInstance(
progressDialogMessage, progressDialogMessage,
progressDialogStyle, progressDialogStyle,
cancelable); cancelable);
}
public void showProgressDialog(FragmentActivity activity) {
if (mProgressDialogFragment == null) {
return;
}
// TODO: This is a hack!, see // TODO: This is a hack!, see
// http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
final FragmentManager manager = activity.getSupportFragmentManager(); final FragmentManager manager = mActivity.getSupportFragmentManager();
Handler handler = new Handler(); Handler handler = new Handler();
handler.post(new Runnable() { handler.post(new Runnable() {
public void run() { public void run() {
mProgressDialogFragment.show(manager, "progressDialog"); frag.show(manager, "progressDialog");
} }
}); });
} }
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
Bundle data = message.getData(); Bundle data = message.getData();
if (mProgressDialogFragment == null) { ProgressDialogFragment progressDialogFragment =
// Log.e(Constants.TAG, (ProgressDialogFragment) mActivity.getSupportFragmentManager()
// "Progress has not been updated because mProgressDialogFragment was null!"); .findFragmentByTag("progressDialog");
if (progressDialogFragment == null) {
Log.e(Constants.TAG, "Progress has not been updated because mProgressDialogFragment was null!");
return; return;
} }
MessageStatus status = MessageStatus.fromInt(message.arg1); MessageStatus status = MessageStatus.fromInt(message.arg1);
switch (status) { switch (status) {
case OKAY: case OKAY:
mProgressDialogFragment.dismissAllowingStateLoss(); progressDialogFragment.dismissAllowingStateLoss();
break; break;
case EXCEPTION: case EXCEPTION:
mProgressDialogFragment.dismissAllowingStateLoss(); progressDialogFragment.dismissAllowingStateLoss();
// show error from service // show error from service
if (data.containsKey(DATA_ERROR)) { if (data.containsKey(DATA_ERROR)) {
@ -142,13 +130,13 @@ public class ServiceProgressHandler extends Handler {
// update progress from service // update progress from service
if (data.containsKey(DATA_MESSAGE)) { if (data.containsKey(DATA_MESSAGE)) {
mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE), progressDialogFragment.setProgress(data.getString(DATA_MESSAGE),
data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
} else if (data.containsKey(DATA_MESSAGE_ID)) { } else if (data.containsKey(DATA_MESSAGE_ID)) {
mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID), progressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID),
data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
} else { } else {
mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS), progressDialogFragment.setProgress(data.getInt(DATA_PROGRESS),
data.getInt(DATA_PROGRESS_MAX)); data.getInt(DATA_PROGRESS_MAX));
} }
} }
@ -156,7 +144,7 @@ public class ServiceProgressHandler extends Handler {
break; break;
case PREVENT_CANCEL: case PREVENT_CANCEL:
mProgressDialogFragment.setPreventCancel(true); progressDialogFragment.setPreventCancel(true);
break; break;
default: default:

View File

@ -64,7 +64,8 @@ import org.sufficientlysecure.keychain.util.Preferences;
import java.util.ArrayList; import java.util.ArrayList;
public class CertifyKeyFragment extends CachingCryptoOperationFragment<CertifyActionsParcel> public class CertifyKeyFragment
extends CachingCryptoOperationFragment<CertifyActionsParcel, CertifyResult>
implements LoaderManager.LoaderCallbacks<Cursor> { implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_CHECK_STATES = "check_states"; public static final String ARG_CHECK_STATES = "check_states";
@ -89,7 +90,6 @@ public class CertifyKeyFragment extends CachingCryptoOperationFragment<CertifyAc
private static final int INDEX_IS_REVOKED = 4; private static final int INDEX_IS_REVOKED = 4;
private MultiUserIdsAdapter mUserIdsAdapter; private MultiUserIdsAdapter mUserIdsAdapter;
private Messenger mPassthroughMessenger;
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
@ -102,10 +102,6 @@ public class CertifyKeyFragment extends CachingCryptoOperationFragment<CertifyAc
return; return;
} }
mPassthroughMessenger = getActivity().getIntent().getParcelableExtra(
KeychainService.EXTRA_MESSENGER);
mPassthroughMessenger = null; // TODO doesn't work with CryptoOperationFragment, disabled for now
ArrayList<Boolean> checkedStates; ArrayList<Boolean> checkedStates;
if (savedInstanceState != null) { if (savedInstanceState != null) {
checkedStates = (ArrayList<Boolean>) savedInstanceState.getSerializable(ARG_CHECK_STATES); checkedStates = (ArrayList<Boolean>) savedInstanceState.getSerializable(ARG_CHECK_STATES);
@ -306,97 +302,39 @@ public class CertifyKeyFragment extends CachingCryptoOperationFragment<CertifyAc
} }
@Override @Override
protected void cryptoOperation(CryptoInputParcel cryptoInput, CertifyActionsParcel actionsParcel) { protected CertifyActionsParcel createOperationInput() {
Bundle data = new Bundle();
{
if (actionsParcel == null) { // Bail out if there is not at least one user id selected
// Bail out if there is not at least one user id selected ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions(); if (certifyActions.isEmpty()) {
if (certifyActions.isEmpty()) { Notify.create(getActivity(), "No identities selected!",
Notify.create(getActivity(), "No identities selected!", Notify.Style.ERROR).show();
Notify.Style.ERROR).show(); return null;
return;
}
long selectedKeyId = mCertifyKeySpinner.getSelectedKeyId();
// fill values for this action
actionsParcel = new CertifyActionsParcel(selectedKeyId);
actionsParcel.mCertifyActions.addAll(certifyActions);
// cached for next cryptoOperation loop
cacheActionsParcel(actionsParcel);
}
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
data.putParcelable(KeychainService.CERTIFY_PARCEL, actionsParcel);
if (mUploadKeyCheckbox.isChecked()) {
String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver();
data.putString(KeychainService.UPLOAD_KEY_SERVER, keyserver);
}
} }
// Send all information needed to service to sign key in other thread long selectedKeyId = mCertifyKeySpinner.getSelectedKeyId();
Intent intent = new Intent(getActivity(), KeychainService.class);
intent.setAction(KeychainService.ACTION_CERTIFY_KEYRING);
intent.putExtra(KeychainService.EXTRA_DATA, data);
if (mPassthroughMessenger != null) { // fill values for this action
intent.putExtra(KeychainService.EXTRA_MESSENGER, mPassthroughMessenger); CertifyActionsParcel actionsParcel = new CertifyActionsParcel(selectedKeyId);
} else { actionsParcel.mCertifyActions.addAll(certifyActions);
// Message is received after signing is done in KeychainService // cached for next cryptoOperation loop
ServiceProgressHandler saveHandler = new ServiceProgressHandler( cacheActionsParcel(actionsParcel);
getActivity(),
getString(R.string.progress_certifying),
ProgressDialog.STYLE_SPINNER,
true
) {
@Override
public void handleMessage(Message message) {
// handle messages by KeychainIntentCryptoServiceHandler first
super.handleMessage(message);
// handle pending messages return actionsParcel;
if (handlePendingMessage(message)) { }
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
Bundle data = message.getData();
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
Intent intent = new Intent();
intent.putExtra(CertifyResult.EXTRA_RESULT, result);
getActivity().setResult(Activity.RESULT_OK, intent);
getActivity().finish();
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
saveHandler.showProgressDialog(getActivity());
}
// start service with intent
getActivity().startService(intent);
if (mPassthroughMessenger != null) {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
}
@Override
protected void onCryptoOperationSuccess(CertifyResult result) {
Intent intent = new Intent();
intent.putExtra(CertifyResult.EXTRA_RESULT, result);
getActivity().setResult(Activity.RESULT_OK, intent);
getActivity().finish();
} }
@Override @Override
protected void onCryptoOperationCancelled() { protected void onCryptoOperationCancelled() {
super.onCryptoOperationCancelled(); super.onCryptoOperationCancelled();
} }
} }

View File

@ -49,11 +49,7 @@ public class ConsolidateDialogActivity extends FragmentActivity {
private void consolidateRecovery(boolean recovery) { private void consolidateRecovery(boolean recovery) {
// Message is received after importing is done in KeychainService // Message is received after importing is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
this,
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -94,7 +90,10 @@ public class ConsolidateDialogActivity extends FragmentActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(this); saveHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, false
);
// start service with intent // start service with intent
startService(intent); startService(intent);

View File

@ -197,11 +197,7 @@ public class CreateKeyFinalFragment extends Fragment {
Intent intent = new Intent(getActivity(), KeychainService.class); Intent intent = new Intent(getActivity(), KeychainService.class);
intent.setAction(KeychainService.ACTION_EDIT_KEYRING); intent.setAction(KeychainService.ACTION_EDIT_KEYRING);
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_building_key),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -245,7 +241,8 @@ public class CreateKeyFinalFragment extends Fragment {
Messenger messenger = new Messenger(saveHandler); Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
saveHandler.showProgressDialog(getActivity()); saveHandler.showProgressDialog(getString(R.string.progress_building_key),
ProgressDialog.STYLE_HORIZONTAL, false);
getActivity().startService(intent); getActivity().startService(intent);
} }
@ -271,11 +268,7 @@ public class CreateKeyFinalFragment extends Fragment {
intent.putExtra(KeychainService.EXTRA_DATA, data); intent.putExtra(KeychainService.EXTRA_DATA, data);
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_uploading),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -301,10 +294,13 @@ public class CreateKeyFinalFragment extends Fragment {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(getActivity()); saveHandler.showProgressDialog(
getString(R.string.progress_uploading),
ProgressDialog.STYLE_HORIZONTAL, false);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);
} }
} }

View File

@ -176,11 +176,7 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe
public void importKey() { public void importKey() {
// Message is received after decrypting is done in KeychainService // Message is received after decrypting is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -243,7 +239,10 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe
Messenger messenger = new Messenger(saveHandler); Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
saveHandler.showProgressDialog(getActivity()); saveHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, false
);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);

View File

@ -63,8 +63,6 @@ public class DecryptFilesFragment extends DecryptFragment {
private Uri mInputUri = null; private Uri mInputUri = null;
private Uri mOutputUri = null; private Uri mOutputUri = null;
private String mCurrentCryptoOperation;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */
@ -151,7 +149,7 @@ public class DecryptFilesFragment extends DecryptFragment {
return; return;
} }
startDecryptFilenames(); cryptoOperation();
} }
private String removeEncryptedAppend(String name) { private String removeEncryptedAppend(String name) {
@ -179,112 +177,6 @@ public class DecryptFilesFragment extends DecryptFragment {
} }
} }
private void startDecrypt() {
mCurrentCryptoOperation = KeychainService.ACTION_DECRYPT_VERIFY;
cryptoOperation(new CryptoInputParcel());
}
private void startDecryptFilenames() {
mCurrentCryptoOperation = KeychainService.ACTION_DECRYPT_METADATA;
cryptoOperation(new CryptoInputParcel());
}
@Override
@SuppressLint("HandlerLeak")
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
// Send all information needed to service to decrypt in other thread
Intent intent = new Intent(getActivity(), KeychainService.class);
// fill values for this action
Bundle data = new Bundle();
// use current operation, either decrypt metadata or decrypt payload
intent.setAction(mCurrentCryptoOperation);
// data
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mInputUri, mOutputUri)
.setAllowSymmetricDecryption(true);
data.putParcelable(KeychainService.DECRYPT_VERIFY_PARCEL, input);
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after decrypting is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_decrypting),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
// handle pending messages
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
// get returned data bundle
Bundle returnData = message.getData();
DecryptVerifyResult pgpResult =
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
if (pgpResult.success()) {
switch (mCurrentCryptoOperation) {
case KeychainService.ACTION_DECRYPT_METADATA: {
askForOutputFilename(pgpResult.getDecryptMetadata().getFilename());
break;
}
case KeychainService.ACTION_DECRYPT_VERIFY: {
// display signature result in activity
loadVerifyResult(pgpResult);
if (mDeleteAfter.isChecked()) {
// Create and show dialog to delete original file
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri);
deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
setInputUri(null);
}
/*
// A future open after decryption feature
if () {
Intent viewFile = new Intent(Intent.ACTION_VIEW);
viewFile.setInputData(mOutputUri);
startActivity(viewFile);
}
*/
break;
}
default: {
Log.e(Constants.TAG, "Bug: not supported operation!");
break;
}
}
}
pgpResult.createNotify(getActivity()).show(DecryptFilesFragment.this);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
saveHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {
@ -299,7 +191,7 @@ public class DecryptFilesFragment extends DecryptFragment {
// This happens after output file was selected, so start our operation // This happens after output file was selected, so start our operation
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mOutputUri = data.getData(); mOutputUri = data.getData();
startDecrypt(); cryptoOperation();
} }
return; return;
} }
@ -314,4 +206,20 @@ public class DecryptFilesFragment extends DecryptFragment {
protected void onVerifyLoaded(boolean hideErrorOverlay) { protected void onVerifyLoaded(boolean hideErrorOverlay) {
} }
@Override
protected PgpDecryptVerifyInputParcel createOperationInput() {
return new PgpDecryptVerifyInputParcel(mInputUri, mOutputUri).setAllowSymmetricDecryption(true);
}
@Override
protected void onCryptoOperationSuccess(DecryptVerifyResult result) {
// display signature result in activity
loadVerifyResult(result);
// TODO delete after decrypt not implemented!
}
} }

View File

@ -43,12 +43,14 @@ 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.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;
@ -56,8 +58,9 @@ 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 extends CryptoOperationFragment implements public abstract class DecryptFragment
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";

View File

@ -17,11 +17,8 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -35,9 +32,6 @@ 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.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
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;
@ -115,7 +109,7 @@ public class DecryptTextFragment extends DecryptFragment {
mShowMenuOptions = args.getBoolean(ARG_SHOW_MENU, false); mShowMenuOptions = args.getBoolean(ARG_SHOW_MENU, false);
if (savedInstanceState == null) { if (savedInstanceState == null) {
cryptoOperation(new CryptoInputParcel()); cryptoOperation();
} }
} }
@ -158,77 +152,8 @@ public class DecryptTextFragment extends DecryptFragment {
} }
@Override @Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) { protected PgpDecryptVerifyInputParcel createOperationInput() {
// Send all information needed to service to decrypt in other thread return new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
Intent intent = new Intent(getActivity(), KeychainService.class);
// fill values for this action
Bundle data = new Bundle();
intent.setAction(KeychainService.ACTION_DECRYPT_VERIFY);
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
data.putParcelable(KeychainService.DECRYPT_VERIFY_PARCEL, input);
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_decrypting),
ProgressDialog.STYLE_HORIZONTAL
) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
// handle pending messages
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
// get returned data bundle
Bundle returnData = message.getData();
DecryptVerifyResult pgpResult =
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
if (pgpResult.success()) {
byte[] decryptedMessage = pgpResult.getOutputBytes();
String displayMessage;
if (pgpResult.getCharset() != null) {
try {
displayMessage = new String(decryptedMessage, pgpResult.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(pgpResult);
} else {
// TODO: show also invalid layout with different text?
}
pgpResult.createNotify(getActivity()).show(DecryptTextFragment.this);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
saveHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
} }
@Override @Override
@ -236,4 +161,27 @@ public class DecryptTextFragment extends DecryptFragment {
mShowMenuOptions = hideErrorOverlay; mShowMenuOptions = hideErrorOverlay;
getActivity().supportInvalidateOptionsMenu(); 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);
}
} }

View File

@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.os.Parcelable;
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;
@ -39,6 +40,9 @@ import android.widget.ListView;
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.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.SingletonResult; import org.sufficientlysecure.keychain.operations.results.SingletonResult;
@ -66,9 +70,8 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel, OperationResult>
public class EditKeyFragment extends CryptoOperationFragment implements implements LoaderManager.LoaderCallbacks<Cursor> {
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri"; public static final String ARG_DATA_URI = "uri";
public static final String ARG_SAVE_KEYRING_PARCEL = "save_keyring_parcel"; public static final String ARG_SAVE_KEYRING_PARCEL = "save_keyring_parcel";
@ -572,7 +575,7 @@ public class EditKeyFragment extends CryptoOperationFragment implements
addSubkeyDialogFragment.show(getActivity().getSupportFragmentManager(), "addSubkeyDialog"); addSubkeyDialogFragment.show(getActivity().getSupportFragmentManager(), "addSubkeyDialog");
} }
private void returnKeyringParcel() { protected void returnKeyringParcel() {
if (mSaveKeyringParcel.mAddUserIds.size() == 0) { if (mSaveKeyringParcel.mAddUserIds.size() == 0) {
Notify.create(getActivity(), R.string.edit_key_error_add_identity, Notify.Style.ERROR).show(); Notify.create(getActivity(), R.string.edit_key_error_add_identity, Notify.Style.ERROR).show();
return; return;
@ -591,76 +594,6 @@ public class EditKeyFragment extends CryptoOperationFragment implements
getActivity().finish(); getActivity().finish();
} }
@Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
Log.d(Constants.TAG, "cryptoInput:\n" + cryptoInput);
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel);
ServiceProgressHandler saveHandler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_saving),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
// get returned data bundle
Bundle returnData = message.getData();
if (returnData == null) {
return;
}
final OperationResult result =
returnData.getParcelable(OperationResult.EXTRA_RESULT);
if (result == null) {
return;
}
// if bad -> display here!
if (!result.success()) {
result.createNotify(getActivity()).show();
return;
}
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
intent.putExtra(OperationResult.EXTRA_RESULT, result);
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
getActivity().finish();
}
}
};
// Send all information needed to service to import key in other thread
Intent intent = new Intent(getActivity(), KeychainService.class);
intent.setAction(KeychainService.ACTION_EDIT_KEYRING);
// fill values for this action
Bundle data = new Bundle();
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
data.putParcelable(KeychainService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel);
intent.putExtra(KeychainService.EXTRA_DATA, data);
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
saveHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
}
/** /**
* Closes this activity, returning a result parcel with a single error log entry. * Closes this activity, returning a result parcel with a single error log entry.
*/ */
@ -675,4 +608,20 @@ public class EditKeyFragment extends CryptoOperationFragment implements
getActivity().finish(); getActivity().finish();
} }
@Override
protected SaveKeyringParcel createOperationInput() {
return mSaveKeyringParcel;
}
@Override
protected void onCryptoOperationSuccess(OperationResult result) {
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
intent.putExtra(OperationResult.EXTRA_RESULT, result);
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
getActivity().finish();
}
} }

View File

@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -26,8 +25,6 @@ import android.graphics.Point;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@ -49,9 +46,6 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpConstants; import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration; import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
@ -72,7 +66,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEncryptParcel> { public class EncryptFilesFragment
extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> {
public static final String ARG_DELETE_AFTER_ENCRYPT = "delete_after_encrypt"; public static final String ARG_DELETE_AFTER_ENCRYPT = "delete_after_encrypt";
public static final String ARG_ENCRYPT_FILENAMES = "encrypt_filenames"; public static final String ARG_ENCRYPT_FILENAMES = "encrypt_filenames";
@ -272,11 +267,13 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.encrypt_save: { case R.id.encrypt_save: {
cryptoOperation(false); mShareAfterEncrypt = false;
cryptoOperation();
break; break;
} }
case R.id.encrypt_share: { case R.id.encrypt_share: {
cryptoOperation(true); mShareAfterEncrypt = true;
cryptoOperation();
break; break;
} }
case R.id.check_use_armor: { case R.id.check_use_armor: {
@ -374,7 +371,9 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
} }
public void onEncryptSuccess(final SignEncryptResult result) { @Override
protected void onCryptoOperationSuccess(final SignEncryptResult result) {
if (mDeleteAfterEncrypt) { if (mDeleteAfterEncrypt) {
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment deleteFileDialog =
DeleteFileDialogFragment.newInstance(mFilesAdapter.getAsArrayList()); DeleteFileDialogFragment.newInstance(mFilesAdapter.getAsArrayList());
@ -402,6 +401,7 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
result.createNotify(getActivity()).show(); result.createNotify(getActivity()).show();
} }
} }
} }
// prepares mOutputUris, either directly and returns false, or indirectly // prepares mOutputUris, either directly and returns false, or indirectly
@ -441,7 +441,46 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
} }
} }
protected SignEncryptParcel createIncompleteEncryptBundle() { protected SignEncryptParcel createOperationInput() {
SignEncryptParcel actionsParcel = getCachedActionsParcel();
// we have three cases here: nothing cached, cached except output, fully cached
if (actionsParcel == null) {
// clear output uris for now, they will be created by prepareOutputStreams later
mOutputUris = null;
actionsParcel = createIncompleteCryptoInput();
// this is null if invalid, just return in that case
if (actionsParcel == null) {
return null;
}
cacheActionsParcel(actionsParcel);
}
// if it's incomplete, prepare output streams
if (actionsParcel.isIncomplete()) {
// if this is still null, prepare output streams again
if (mOutputUris == null) {
// this may interrupt the flow, and call us again from onActivityResult
if (prepareOutputStreams(mShareAfterEncrypt)) {
return null;
}
}
actionsParcel.addOutputUris(mOutputUris);
cacheActionsParcel(actionsParcel);
}
return actionsParcel;
}
protected SignEncryptParcel createIncompleteCryptoInput() {
// fill values for this action // fill values for this action
SignEncryptParcel data = new SignEncryptParcel(); SignEncryptParcel data = new SignEncryptParcel();
@ -546,92 +585,6 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
return sendIntent; return sendIntent;
} }
public void cryptoOperation(boolean share) {
mShareAfterEncrypt = share;
cryptoOperation();
}
@Override
protected void cryptoOperation(CryptoInputParcel cryptoInput, SignEncryptParcel actionsParcel) {
// we have three cases here: nothing cached, cached except output, fully cached
if (actionsParcel == null) {
// clear output uris for now, they will be created by prepareOutputStreams later
mOutputUris = null;
actionsParcel = createIncompleteEncryptBundle();
// this is null if invalid, just return in that case
if (actionsParcel == null) {
// Notify was created by createEncryptBundle.
return;
}
cacheActionsParcel(actionsParcel);
}
// if it's incomplete, prepare output streams
if (actionsParcel.isIncomplete()) {
// if this is still null, prepare output streams again
if (mOutputUris == null) {
// this may interrupt the flow, and call us again from onActivityResult
if (prepareOutputStreams(mShareAfterEncrypt)) {
return;
}
}
actionsParcel.addOutputUris(mOutputUris);
cacheActionsParcel(actionsParcel);
}
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainService.class);
intent.setAction(KeychainService.ACTION_SIGN_ENCRYPT);
Bundle data = new Bundle();
data.putParcelable(KeychainService.SIGN_ENCRYPT_PARCEL, actionsParcel);
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainService
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_encrypting),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
// handle pending messages
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
SignEncryptResult result =
message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT);
if (result.success()) {
onEncryptSuccess(result);
} else {
result.createNotify(getActivity()).show();
}
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(serviceHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
serviceHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {
@ -646,7 +599,8 @@ public class EncryptFilesFragment extends CachingCryptoOperationFragment<SignEnc
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mOutputUris = new ArrayList<>(1); mOutputUris = new ArrayList<>(1);
mOutputUris.add(data.getData()); mOutputUris.add(data.getData());
cryptoOperation(false); mShareAfterEncrypt = false;
cryptoOperation();
} }
return; return;
} }

View File

@ -18,11 +18,8 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -41,9 +38,6 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpConstants; import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
@ -55,7 +49,8 @@ import org.sufficientlysecure.keychain.util.ShareHelper;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class EncryptTextFragment extends CachingCryptoOperationFragment<SignEncryptParcel> { public class EncryptTextFragment
extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> {
public static final String ARG_TEXT = "text"; public static final String ARG_TEXT = "text";
public static final String ARG_USE_COMPRESSION = "use_compression"; public static final String ARG_USE_COMPRESSION = "use_compression";
@ -145,6 +140,7 @@ public class EncryptTextFragment extends CachingCryptoOperationFragment<SignEncr
} }
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@Override @Override
@ -168,11 +164,13 @@ public class EncryptTextFragment extends CachingCryptoOperationFragment<SignEncr
// break; // break;
// } // }
case R.id.encrypt_copy: { case R.id.encrypt_copy: {
cryptoOperation(false); mShareAfterEncrypt = false;
cryptoOperation();
break; break;
} }
case R.id.encrypt_share: { case R.id.encrypt_share: {
cryptoOperation(true); mShareAfterEncrypt = true;
cryptoOperation();
break; break;
} }
default: { default: {
@ -204,21 +202,7 @@ public class EncryptTextFragment extends CachingCryptoOperationFragment<SignEncr
} }
protected void onEncryptSuccess(SignEncryptResult result) { protected SignEncryptParcel createOperationInput() {
if (mShareAfterEncrypt) {
// Share encrypted message/file
startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes()));
} else {
// Copy to clipboard
copyToClipboard(result.getResultBytes());
result.createNotify(getActivity()).show();
// Notify.create(EncryptTextActivity.this,
// R.string.encrypt_sign_clipboard_successful, Notify.Style.OK)
// .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));
}
}
protected SignEncryptParcel createEncryptBundle() {
if (mMessage == null || mMessage.isEmpty()) { if (mMessage == null || mMessage.isEmpty()) {
Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR) Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
@ -331,71 +315,21 @@ public class EncryptTextFragment extends CachingCryptoOperationFragment<SignEncr
return sendIntent; return sendIntent;
} }
public void cryptoOperation(boolean share) {
mShareAfterEncrypt = share;
cryptoOperation();
}
@Override @Override
protected void cryptoOperation(CryptoInputParcel cryptoInput, SignEncryptParcel actionsParcel) { protected void onCryptoOperationSuccess(SignEncryptResult result) {
if (actionsParcel == null) { if (mShareAfterEncrypt) {
// Share encrypted message/file
actionsParcel = createEncryptBundle(); startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes()));
// this is null if invalid, just return in that case } else {
if (actionsParcel == null) { // Copy to clipboard
// Notify was created by inputIsValid. copyToClipboard(result.getResultBytes());
return; result.createNotify(getActivity()).show();
} // Notify.create(EncryptTextActivity.this,
// R.string.encrypt_sign_clipboard_successful, Notify.Style.OK)
cacheActionsParcel(actionsParcel); // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));
} }
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainService.class);
intent.setAction(KeychainService.ACTION_SIGN_ENCRYPT);
Bundle data = new Bundle();
data.putParcelable(KeychainService.SIGN_ENCRYPT_PARCEL, actionsParcel);
data.putParcelable(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after encrypting is done in KeychainService
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_encrypting),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
SignEncryptResult result =
message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT);
if (result.success()) {
onEncryptSuccess(result);
} else {
result.createNotify(getActivity()).show();
}
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(serviceHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
serviceHandler.showProgressDialog(getActivity());
// start service with intent
getActivity().startService(intent);
} }
} }

View File

@ -388,12 +388,7 @@ public class ImportKeysActivity extends BaseNfcActivity {
return; return;
} }
ServiceProgressHandler serviceHandler = new ServiceProgressHandler( ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
this,
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -435,7 +430,11 @@ public class ImportKeysActivity extends BaseNfcActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
serviceHandler.showProgressDialog(this); serviceHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL,
true
);
// start service with intent // start service with intent
startService(intent); startService(intent);
@ -469,7 +468,10 @@ public class ImportKeysActivity extends BaseNfcActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
serviceHandler.showProgressDialog(this); serviceHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, true
);
// start service with intent // start service with intent
startService(intent); startService(intent);

View File

@ -206,12 +206,7 @@ public class ImportKeysProxyActivity extends FragmentActivity {
private void startImportService(ArrayList<ParcelableKeyRing> keyRings) { private void startImportService(ArrayList<ParcelableKeyRing> keyRings) {
// Message is received after importing is done in KeychainService // Message is received after importing is done in KeychainService
ServiceProgressHandler serviceHandler = new ServiceProgressHandler( ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
this,
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -273,7 +268,9 @@ public class ImportKeysProxyActivity extends FragmentActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
serviceHandler.showProgressDialog(this); serviceHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, true);
// start service with intent // start service with intent
startService(intent); startService(intent);

View File

@ -572,12 +572,7 @@ public class KeyListFragment extends LoaderFragment
keyList.add(keyEntry); keyList.add(keyEntry);
} }
ServiceProgressHandler serviceHandler = new ServiceProgressHandler( ServiceProgressHandler serviceHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_updating),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -625,7 +620,9 @@ public class KeyListFragment extends LoaderFragment
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
serviceHandler.showProgressDialog(getActivity()); serviceHandler.showProgressDialog(
getString(R.string.progress_updating),
ProgressDialog.STYLE_HORIZONTAL, true);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);
@ -633,11 +630,7 @@ public class KeyListFragment extends LoaderFragment
private void consolidate() { private void consolidate() {
// Message is received after importing is done in KeychainService // Message is received after importing is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -675,7 +668,9 @@ public class KeyListFragment extends LoaderFragment
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(getActivity()); saveHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, false);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);

View File

@ -124,12 +124,7 @@ public class SafeSlingerActivity extends BaseActivity {
final FragmentActivity activity = SafeSlingerActivity.this; final FragmentActivity activity = SafeSlingerActivity.this;
// Message is received after importing is done in KeychainService // Message is received after importing is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(activity) {
activity,
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -202,7 +197,10 @@ public class SafeSlingerActivity extends BaseActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(activity); saveHandler.showProgressDialog(
getString(R.string.progress_importing),
ProgressDialog.STYLE_HORIZONTAL, true
);
// start service with intent // start service with intent
activity.startService(intent); activity.startService(intent);

View File

@ -108,11 +108,7 @@ public class UploadKeyActivity extends BaseActivity {
intent.putExtra(KeychainService.EXTRA_DATA, data); intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after uploading is done in KeychainService // Message is received after uploading is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
this,
getString(R.string.progress_uploading),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -132,7 +128,9 @@ public class UploadKeyActivity extends BaseActivity {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(this); saveHandler.showProgressDialog(
getString(R.string.progress_uploading),
ProgressDialog.STYLE_HORIZONTAL, false);
// start service with intent // start service with intent
startService(intent); startService(intent);

View File

@ -698,9 +698,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Messenger messenger = new Messenger(serviceHandler); Messenger messenger = new Messenger(serviceHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog
serviceHandler.showProgressDialog(this);
// start service with intent // start service with intent
startService(intent); startService(intent);

View File

@ -360,12 +360,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
mProofVerifyDetail.setVisibility(View.GONE); mProofVerifyDetail.setVisibility(View.GONE);
// Create a new Messenger for the communication back after proof work is done // Create a new Messenger for the communication back after proof work is done
// ServiceProgressHandler handler = new ServiceProgressHandler(getActivity()) {
ServiceProgressHandler handler = new ServiceProgressHandler(
getActivity(),
getString(R.string.progress_verifying_signature),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -454,7 +449,10 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
handler.showProgressDialog(getActivity()); handler.showProgressDialog(
getString(R.string.progress_verifying_signature),
ProgressDialog.STYLE_HORIZONTAL, false
);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);

View File

@ -2,24 +2,18 @@ package org.sufficientlysecure.keychain.ui.base;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message;
import android.os.Parcelable; import android.os.Parcelable;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
public abstract class CachingCryptoOperationFragment <T extends Parcelable> extends CryptoOperationFragment { public abstract class CachingCryptoOperationFragment <T extends Parcelable, S extends OperationResult>
extends CryptoOperationFragment<T, S> {
public static final String ARG_CACHED_ACTIONS = "cached_actions"; public static final String ARG_CACHED_ACTIONS = "cached_actions";
private T mCachedActionsParcel; private T mCachedActionsParcel;
@Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
cryptoOperation(cryptoInput, mCachedActionsParcel);
}
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
@ -37,21 +31,16 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable> exte
} }
@Override @Override
public boolean handlePendingMessage(Message message) { protected void onCryptoOperationResult(S result) {
// see if it's an InputPendingResult, and if so don't care super.onCryptoOperationResult(result);
if (super.handlePendingMessage(message)) { mCachedActionsParcel = null;
return true;
}
// if it's a non-input-pending OKAY message, always clear the cached actions parcel
if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) {
mCachedActionsParcel = null;
}
return false;
} }
protected abstract void cryptoOperation(CryptoInputParcel cryptoInput, T cachedActionsParcel); protected abstract T createOperationInput();
protected T getCachedActionsParcel() {
return mCachedActionsParcel;
}
protected void cacheActionsParcel(T cachedActionsParcel) { protected void cacheActionsParcel(T cachedActionsParcel) {
mCachedActionsParcel = cachedActionsParcel; mCachedActionsParcel = cachedActionsParcel;

View File

@ -19,24 +19,32 @@
package org.sufficientlysecure.keychain.ui.base; package org.sufficientlysecure.keychain.ui.base;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.KeychainNewService;
import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.NfcOperationActivity; import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
/** /**
* All fragments executing crypto operations need to extend this class. * All fragments executing crypto operations need to extend this class.
*/ */
public abstract class CryptoOperationFragment extends Fragment { public abstract class CryptoOperationFragment <T extends Parcelable, S extends OperationResult>
extends Fragment {
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
public static final int REQUEST_CODE_NFC = 0x00008002; public static final int REQUEST_CODE_NFC = 0x00008002;
@ -99,35 +107,111 @@ public abstract class CryptoOperationFragment extends Fragment {
} }
} }
public boolean handlePendingMessage(Message message) { protected void dismissProgress() {
if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) { ProgressDialogFragment progressDialogFragment =
Bundle data = message.getData(); (ProgressDialogFragment) getFragmentManager().findFragmentByTag("progressDialog");
OperationResult result = data.getParcelable(OperationResult.EXTRA_RESULT); if (progressDialogFragment == null) {
if (result == null || !(result instanceof InputPendingResult)) { return;
return false;
}
InputPendingResult pendingResult = (InputPendingResult) result;
if (pendingResult.isPending()) {
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
initiateInputActivity(requiredInput);
return true;
}
} }
return false; progressDialogFragment.dismissAllowingStateLoss();
}
protected abstract T createOperationInput();
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
T operationInput = createOperationInput();
if (operationInput == null) {
return;
}
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(getActivity(), KeychainNewService.class);
intent.putExtra(KeychainNewService.EXTRA_OPERATION_INPUT, operationInput);
intent.putExtra(KeychainNewService.EXTRA_CRYPTO_INPUT, cryptoInput);
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
@Override
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
// get returned data bundle
Bundle returnData = message.getData();
if (returnData == null) {
return;
}
final OperationResult result =
returnData.getParcelable(OperationResult.EXTRA_RESULT);
onHandleResult(result);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
saveHandler.showProgressDialog(
getString(R.string.progress_building_key),
ProgressDialog.STYLE_HORIZONTAL, false);
getActivity().startService(intent);
} }
protected void cryptoOperation() { protected void cryptoOperation() {
cryptoOperation(new CryptoInputParcel()); cryptoOperation(new CryptoInputParcel());
} }
protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); protected void onCryptoOperationResult(S result) {
if (result.success()) {
protected void onCryptoOperationCancelled() { onCryptoOperationSuccess(result);
// Nothing to do here, in most cases } else {
onCryptoOperationError(result);
}
} }
abstract protected void onCryptoOperationSuccess(S result);
protected void onCryptoOperationError(S result) {
result.createNotify(getActivity()).show();
}
protected void onCryptoOperationCancelled() {
}
public void onHandleResult(OperationResult result) {
if (result instanceof InputPendingResult) {
InputPendingResult pendingResult = (InputPendingResult) result;
if (pendingResult.isPending()) {
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
initiateInputActivity(requiredInput);
return;
}
}
dismissProgress();
try {
// noinspection unchecked, because type erasure :(
onCryptoOperationResult((S) result);
} catch (ClassCastException e) {
throw new AssertionError("bad return class ("
+ result.getClass().getSimpleName() + "), this is a programming error!");
}
}
} }

View File

@ -135,12 +135,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
intent.setAction(KeychainService.ACTION_DELETE); intent.setAction(KeychainService.ACTION_DELETE);
// Message is received after importing is done in KeychainService // Message is received after importing is done in KeychainService
ServiceProgressHandler saveHandler = new ServiceProgressHandler( ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
getActivity(),
getString(R.string.progress_deleting),
ProgressDialog.STYLE_HORIZONTAL,
true
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
super.handleMessage(message); super.handleMessage(message);
@ -168,7 +163,8 @@ public class DeleteKeyDialogFragment extends DialogFragment {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
saveHandler.showProgressDialog(getActivity()); saveHandler.showProgressDialog(getString(R.string.progress_deleting),
ProgressDialog.STYLE_HORIZONTAL, true);
// start service with intent // start service with intent
getActivity().startService(intent); getActivity().startService(intent);

View File

@ -97,10 +97,7 @@ public class ExportHelper {
intent.putExtra(KeychainService.EXTRA_DATA, data); intent.putExtra(KeychainService.EXTRA_DATA, data);
// Message is received after exporting is done in KeychainService // Message is received after exporting is done in KeychainService
ServiceProgressHandler exportHandler = new ServiceProgressHandler(mActivity, ServiceProgressHandler exportHandler = new ServiceProgressHandler(mActivity) {
mActivity.getString(R.string.progress_exporting),
ProgressDialog.STYLE_HORIZONTAL
) {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first // handle messages by standard KeychainIntentServiceHandler first
@ -121,7 +118,10 @@ public class ExportHelper {
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
exportHandler.showProgressDialog(mActivity); exportHandler.showProgressDialog(
mActivity.getString(R.string.progress_exporting),
ProgressDialog.STYLE_HORIZONTAL, false
);
// start service with intent // start service with intent
mActivity.startService(intent); mActivity.startService(intent);

View File

@ -341,6 +341,7 @@
<item quantity="other">"exporting keys…"</item> <item quantity="other">"exporting keys…"</item>
</plurals> </plurals>
<string name="progress_start">"preparing operation…"</string>
<string name="progress_extracting_signature_key">"extracting signature key…"</string> <string name="progress_extracting_signature_key">"extracting signature key…"</string>
<string name="progress_extracting_key">"extracting key…"</string> <string name="progress_extracting_key">"extracting key…"</string>
<string name="progress_preparing_streams">"preparing streams…"</string> <string name="progress_preparing_streams">"preparing streams…"</string>

View File

@ -158,7 +158,7 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds())); mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null); CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
Assert.assertTrue("certification must succeed", result.success()); Assert.assertTrue("certification must succeed", result.success());
@ -186,7 +186,7 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null, actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null,
mStaticRing2.getPublicKey().getUnorderedUserAttributes())); mStaticRing2.getPublicKey().getUnorderedUserAttributes()));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null); CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
Assert.assertTrue("certification must succeed", result.success()); Assert.assertTrue("certification must succeed", result.success());
@ -209,7 +209,7 @@ public class CertifyOperationTest {
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(), actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds())); mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null); CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
Assert.assertFalse("certification with itself must fail!", result.success()); Assert.assertFalse("certification with itself must fail!", result.success());
Assert.assertTrue("error msg must be about self certification", Assert.assertTrue("error msg must be about self certification",
@ -228,7 +228,7 @@ public class CertifyOperationTest {
uids.add("nonexistent"); uids.add("nonexistent");
actions.add(new CertifyAction(1234L, uids)); actions.add(new CertifyAction(1234L, uids));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null); CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
Assert.assertFalse("certification of nonexistent key must fail", result.success()); Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found", Assert.assertTrue("must contain error msg about not found",
@ -240,7 +240,7 @@ public class CertifyOperationTest {
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(), actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds())); mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null); CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
Assert.assertFalse("certification of nonexistent key must fail", result.success()); Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found", Assert.assertTrue("must contain error msg about not found",