diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org')
41 files changed, 1204 insertions, 503 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java index 20dba95e9..f2516f1bd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java @@ -168,7 +168,7 @@ public class ImportExportOperation extends BaseOperation {              return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, log);          } -        int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0; +        int newKeys = 0, updatedKeys = 0, badKeys = 0, secret = 0;          ArrayList<Long> importedMasterKeyIds = new ArrayList<>();          boolean cancelled = false; @@ -302,7 +302,7 @@ public class ImportExportOperation extends BaseOperation {                  if (!result.success()) {                      badKeys += 1;                  } else if (result.updated()) { -                    oldKeys += 1; +                    updatedKeys += 1;                      importedMasterKeyIds.add(key.getMasterKeyId());                  } else {                      newKeys += 1; @@ -333,7 +333,9 @@ public class ImportExportOperation extends BaseOperation {          }          // Special: make sure new data is synced into contacts -        ContactSyncAdapterService.requestSync(); +        // disabling sync right now since it reduces speed while multi-threading +        // so, we expect calling functions to take care of it. KeychainIntentService handles this +        //ContactSyncAdapterService.requestSync();          // convert to long array          long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()]; @@ -348,18 +350,18 @@ public class ImportExportOperation extends BaseOperation {          }          // special return case: no new keys at all -        if (badKeys == 0 && newKeys == 0 && oldKeys == 0) { +        if (badKeys == 0 && newKeys == 0 && updatedKeys == 0) {              resultType = ImportKeyResult.RESULT_FAIL_NOTHING;          } else {              if (newKeys > 0) {                  resultType |= ImportKeyResult.RESULT_OK_NEWKEYS;              } -            if (oldKeys > 0) { +            if (updatedKeys > 0) {                  resultType |= ImportKeyResult.RESULT_OK_UPDATED;              }              if (badKeys > 0) {                  resultType |= ImportKeyResult.RESULT_WITH_ERRORS; -                if (newKeys == 0 && oldKeys == 0) { +                if (newKeys == 0 && updatedKeys == 0) {                      resultType |= ImportKeyResult.RESULT_ERROR;                  }              } @@ -369,15 +371,15 @@ public class ImportExportOperation extends BaseOperation {          }          // Final log entry, it's easier to do this individually -        if ( (newKeys > 0 || oldKeys > 0) && badKeys > 0) { +        if ( (newKeys > 0 || updatedKeys > 0) && badKeys > 0) {              log.add(LogType.MSG_IMPORT_PARTIAL, 1); -        } else if (newKeys > 0 || oldKeys > 0) { +        } else if (newKeys > 0 || updatedKeys > 0) {              log.add(LogType.MSG_IMPORT_SUCCESS, 1);          } else {              log.add(LogType.MSG_IMPORT_ERROR, 1);          } -        return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret, +        return new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret,                  importedMasterKeyIdsArray);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java index 94684851a..f56fe4bb9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java @@ -120,7 +120,7 @@ public class CertifyResult extends OperationResult {                      mCertifyError, mCertifyError);          } -        return Notify.createNotify(activity, str, duration, style, new ActionListener() { +        return Notify.create(activity, str, duration, style, new ActionListener() {              @Override              public void onAction() {                  Intent intent = new Intent( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index 62197541a..50f49add2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -116,7 +116,7 @@ public class DeleteResult extends OperationResult {              }          } -        return Notify.createNotify(activity, str, duration, style, new ActionListener() { +        return Notify.create(activity, str, duration, style, new ActionListener() {              @Override              public void onAction() {                  Intent intent = new Intent( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java index 2d533ed16..af9f67114 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java @@ -179,7 +179,7 @@ public class ImportKeyResult extends OperationResult {              }          } -        return Notify.createNotify(activity, str, duration, style, new ActionListener() { +        return Notify.create(activity, str, duration, style, new ActionListener() {              @Override              public void onAction() {                  Intent intent = new Intent( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 068e314d5..f2a27b0fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -273,19 +273,19 @@ public abstract class OperationResult implements Parcelable {          }          if (getLog() == null || getLog().isEmpty()) { -            return Notify.createNotify(activity, msgId, Notify.LENGTH_LONG, style); -        } - -        return Notify.createNotify(activity, msgId, Notify.LENGTH_LONG, style, -            new ActionListener() { -                @Override -                public void onAction() { -                    Intent intent = new Intent( -                            activity, LogDisplayActivity.class); -                    intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this); -                    activity.startActivity(intent); -                } -            }, R.string.view_log); +            return Notify.create(activity, msgId, Notify.LENGTH_LONG, style); +        } + +        return Notify.create(activity, msgId, Notify.LENGTH_LONG, style, +                new ActionListener() { +                    @Override +                    public void onAction() { +                        Intent intent = new Intent( +                                activity, LogDisplayActivity.class); +                        intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this); +                        activity.startActivity(intent); +                    } +                }, R.string.view_log);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 98a9ff44f..bd2866985 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -240,6 +240,11 @@ public class OpenPgpService extends RemoteService {          try {              boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); +            Passphrase passphrase = null; +            if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { +                passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); +            } +              byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);              if (nfcSignedHash != null) {                  Log.d(Constants.TAG, "nfcSignedHash:" + Hex.toHexString(nfcSignedHash)); @@ -278,6 +283,7 @@ public class OpenPgpService extends RemoteService {              // sign-only              PgpSignEncryptInput pseInput = new PgpSignEncryptInput() +                    .setSignaturePassphrase(passphrase)                      .setEnableAsciiArmorOutput(asciiArmor)                      .setCleartextSignature(cleartextSign)                      .setDetachedSignature(!cleartextSign) @@ -366,6 +372,11 @@ public class OpenPgpService extends RemoteService {                  compressionId = CompressionAlgorithmTags.UNCOMPRESSED;              } +            Passphrase passphrase = null; +            if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { +                passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); +            } +              // first try to get key ids from non-ambiguous key id extra              long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);              if (keyIds == null) { @@ -391,7 +402,8 @@ public class OpenPgpService extends RemoteService {              InputData inputData = new InputData(is, inputLength, originalFilename);              PgpSignEncryptInput pseInput = new PgpSignEncryptInput(); -            pseInput.setEnableAsciiArmorOutput(asciiArmor) +            pseInput.setSignaturePassphrase(passphrase) +                    .setEnableAsciiArmorOutput(asciiArmor)                      .setVersionHeader(null)                      .setCompressionId(compressionId)                      .setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) @@ -499,6 +511,11 @@ public class OpenPgpService extends RemoteService {                  os = new ParcelFileDescriptor.AutoCloseOutputStream(output);              } +            Passphrase passphrase = null; +            if (data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE) != null) { +                passphrase = new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); +            } +              String currentPkg = getCurrentCallingPackage();              Set<Long> allowedKeyIds;              if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) { @@ -509,7 +526,6 @@ public class OpenPgpService extends RemoteService {                          KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));              } -            Passphrase passphrase = data.getParcelableExtra(OpenPgpApi.EXTRA_PASSPHRASE);              long inputLength = is.available();              InputData inputData = new InputData(is, inputLength); @@ -555,15 +571,16 @@ public class OpenPgpService extends RemoteService {                  }              } else if (pgpResult.success()) {                  Intent result = new Intent(); -                int resultType = OpenPgpApi.RESULT_TYPE_UNENCRYPTED_UNSIGNED;                  OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); +                // TODO: currently RESULT_TYPE_UNENCRYPTED_UNSIGNED is never returned +                // instead an error is returned when no pgp data has been found +                int resultType = OpenPgpApi.RESULT_TYPE_UNENCRYPTED_UNSIGNED;                  if (signatureResult != null) {                      resultType |= OpenPgpApi.RESULT_TYPE_SIGNED;                      if (!signatureResult.isSignatureOnly()) {                          resultType |= OpenPgpApi.RESULT_TYPE_ENCRYPTED;                      } -                    result.putExtra(OpenPgpApi.RESULT_TYPE, resultType);                      result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); @@ -583,7 +600,10 @@ public class OpenPgpService extends RemoteService {                          // If signature key is known, return PendingIntent to show key                          result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(signatureResult.getKeyId()));                      } +                } else { +                    resultType |= OpenPgpApi.RESULT_TYPE_ENCRYPTED;                  } +                result.putExtra(OpenPgpApi.RESULT_TYPE, resultType);                  if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {                      OpenPgpMetadata metadata = pgpResult.getDecryptMetadata(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index 2c5c78161..e8c3e4511 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -186,7 +186,7 @@ public class RemoteServiceActivity extends BaseActivity {                                  // user needs to select a key if it has explicitly requested (None is only allowed for new accounts)                                  if (mUpdateExistingAccount && mAccSettingsFragment.getAccSettings().getKeyId() == Constants.key.none) { -                                    Notify.showNotify(RemoteServiceActivity.this, getString(R.string.api_register_error_select_key), Notify.Style.ERROR); +                                    Notify.create(RemoteServiceActivity.this, getString(R.string.api_register_error_select_key), Notify.Style.ERROR).show();                                  } else {                                      if (mUpdateExistingAccount) {                                          Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CloudImportService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CloudImportService.java new file mode 100644 index 000000000..180109297 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CloudImportService.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.service; + +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.RemoteException; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.ImportExportOperation; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * When this service is started it will initiate a multi-threaded key import and when done it will + * shut itself down. + */ +public class CloudImportService extends Service implements Progressable { + +    //required as extras from intent +    public static final String EXTRA_MESSENGER = "messenger"; +    public static final String EXTRA_DATA = "data"; + +    //required by data bundle +    public static final String IMPORT_KEY_LIST = "import_key_list"; +    public static final String IMPORT_KEY_SERVER = "import_key_server"; + +    // indicates a request to cancel the import +    public static final String ACTION_CANCEL = Constants.INTENT_PREFIX + "CANCEL"; + +    //tells the spawned threads whether the user has requested a cancel +    private static AtomicBoolean mActionCancelled = new AtomicBoolean(false); + +    @Override +    public IBinder onBind(Intent intent) { +        return null; +    } + +    /** +     * Used to accumulate the results of individual key imports +     */ +    private class KeyImportAccumulator { +        private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog(); +        private int mTotalKeys; +        private int mImportedKeys = 0; +        private Progressable mImportProgressable; +        ArrayList<Long> mImportedMasterKeyIds = new ArrayList<Long>(); +        private int mBadKeys = 0; +        private int mNewKeys = 0; +        private int mUpdatedKeys = 0; +        private int mSecret = 0; +        private int mResultType = 0; + +        public KeyImportAccumulator(int totalKeys) { +            mTotalKeys = totalKeys; +            //ignore updates from ImportExportOperation for now +            mImportProgressable = new Progressable() { +                @Override +                public void setProgress(String message, int current, int total) { + +                } + +                @Override +                public void setProgress(int resourceId, int current, int total) { + +                } + +                @Override +                public void setProgress(int current, int total) { + +                } + +                @Override +                public void setPreventCancel() { + +                } +            }; +        } + +        public Progressable getImportProgressable() { +            return mImportProgressable; +        } + +        public int getTotalKeys() { +            return mTotalKeys; +        } + +        public int getImportedKeys() { +            return mImportedKeys; +        } + +        public synchronized void accumulateKeyImport(ImportKeyResult result) { +            mImportedKeys++; +            mImportLog.addAll(result.getLog().toList());//accumulates log +            mBadKeys += result.mBadKeys; +            mNewKeys += result.mNewKeys; +            mUpdatedKeys += result.mUpdatedKeys; +            mSecret += result.mSecret; + +            long[] masterKeyIds = result.getImportedMasterKeyIds(); +            for (int i = 0; i < masterKeyIds.length; i++) { +                mImportedMasterKeyIds.add(masterKeyIds[i]); +            } + +            // if any key import has been cancelled, set result type to cancelled +            // resultType is added to in getConsolidatedKayImport to account for remaining factors +            mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED; + +        } + +        /** +         * returns accumulated result of all imports so far +         * +         * @return +         */ +        public ImportKeyResult getConsolidatedImportKeyResult() { + +            // adding required information to mResultType +            // special case,no keys requested for import +            if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) { +                mResultType = ImportKeyResult.RESULT_FAIL_NOTHING; +            } else { +                if (mNewKeys > 0) { +                    mResultType |= ImportKeyResult.RESULT_OK_NEWKEYS; +                } +                if (mUpdatedKeys > 0) { +                    mResultType |= ImportKeyResult.RESULT_OK_UPDATED; +                } +                if (mBadKeys > 0) { +                    mResultType |= ImportKeyResult.RESULT_WITH_ERRORS; +                    if (mNewKeys == 0 && mUpdatedKeys == 0) { +                        mResultType |= ImportKeyResult.RESULT_ERROR; +                    } +                } +                if (mImportLog.containsWarnings()) { +                    mResultType |= ImportKeyResult.RESULT_WARNINGS; +                } +            } + +            long masterKeyIds[] = new long[mImportedMasterKeyIds.size()]; +            for (int i = 0; i < masterKeyIds.length; i++) { +                masterKeyIds[i] = mImportedMasterKeyIds.get(i); +            } + +            return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys, +                    mSecret, masterKeyIds); +        } + +        public boolean isImportFinished() { +            return mTotalKeys == mImportedKeys; +        } +    } + +    private KeyImportAccumulator mKeyImportAccumulator; + +    Messenger mMessenger; + +    @Override +    public int onStartCommand(Intent intent, int flags, int startId) { + +        if (ACTION_CANCEL.equals(intent.getAction())) { +            mActionCancelled.set(true); +            return Service.START_NOT_STICKY; +        } + +        mActionCancelled.set(false);//we haven't been cancelled, yet + +        Bundle extras = intent.getExtras(); + +        mMessenger = (Messenger) extras.get(EXTRA_MESSENGER); + +        Bundle data = extras.getBundle(EXTRA_DATA); + +        final String keyServer = data.getString(IMPORT_KEY_SERVER); +        //keyList being null (in case key list to be reaad from cache) is checked by importKeys +        final ArrayList<ParcelableKeyRing> keyList = data.getParcelableArrayList(IMPORT_KEY_LIST); + +        // Adding keys to the ThreadPoolExecutor takes time, we don't want to block the main thread +        Thread baseImportThread = new Thread(new Runnable() { + +            @Override +            public void run() { +                importKeys(keyList, keyServer); +            } +        }); +        baseImportThread.start(); +        return Service.START_NOT_STICKY; +    } + +    public void importKeys(ArrayList<ParcelableKeyRing> keyList, final String keyServer) { +        ParcelableFileCache<ParcelableKeyRing> cache = +                new ParcelableFileCache<>(this, "key_import.pcl"); +        int totKeys = 0; +        Iterator<ParcelableKeyRing> keyListIterator = null; +        //either keyList or cache must be null, no guarantees otherwise +        if (keyList == null) {//export from cache, copied from ImportExportOperation.importKeyRings + +            try { +                ParcelableFileCache.IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); +                keyListIterator = it; +                totKeys = it.getSize(); +            } catch (IOException e) { + +                // Special treatment here, we need a lot +                OperationResult.OperationLog log = new OperationResult.OperationLog(); +                log.add(OperationResult.LogType.MSG_IMPORT, 0, 0); +                log.add(OperationResult.LogType.MSG_IMPORT_ERROR_IO, 0, 0); + +                keyImportFailed(new ImportKeyResult(ImportKeyResult.RESULT_ERROR, log)); +            } +        } else { +            keyListIterator = keyList.iterator(); +            totKeys = keyList.size(); +        } + + +        if (keyListIterator != null) { +            mKeyImportAccumulator = new KeyImportAccumulator(totKeys); +            setProgress(0, totKeys); + +            final int maxThreads = 200; +            ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads, +                    30L, TimeUnit.SECONDS, +                    new SynchronousQueue<Runnable>()); + +            while (keyListIterator.hasNext()) { + +                final ParcelableKeyRing pkRing = keyListIterator.next(); + +                Runnable importOperationRunnable = new Runnable() { + +                    @Override +                    public void run() { +                        ImportKeyResult result = null; +                        try { +                            ImportExportOperation importExportOperation = new ImportExportOperation( +                                    CloudImportService.this, +                                    new ProviderHelper(CloudImportService.this), +                                    mKeyImportAccumulator.getImportProgressable(), +                                    mActionCancelled); + +                            ArrayList<ParcelableKeyRing> list = new ArrayList<>(); +                            list.add(pkRing); +                            result = importExportOperation.importKeyRings(list, +                                    keyServer); +                        } finally { +                            // in the off-chance that importKeyRings does something to crash the +                            // thread before it can call singleKeyRingImportCompleted, our imported +                            // key count will go wrong. This will cause the service to never die, +                            // and the progress dialog to stay displayed. The finally block was +                            // originally meant to ensure singleKeyRingImportCompleted was called, +                            // and checks for null were to be introduced, but in such a scenario, +                            // knowing an uncaught error exists in importKeyRings is more important. + +                            // if a null gets passed, something wrong is happening. We want a crash. + +                            singleKeyRingImportCompleted(result); +                        } +                    } +                }; + +                importExecutor.execute(importOperationRunnable); +            } +        } +    } + +    private synchronized void singleKeyRingImportCompleted(ImportKeyResult result) { +        // increase imported key count and accumulate log and bad, new etc. key counts from result +        mKeyImportAccumulator.accumulateKeyImport(result); + +        setProgress(mKeyImportAccumulator.getImportedKeys(), mKeyImportAccumulator.getTotalKeys()); + +        if (mKeyImportAccumulator.isImportFinished()) { +            ContactSyncAdapterService.requestSync(); + +            sendMessageToHandler(ServiceProgressHandler.MessageStatus.OKAY, +                    mKeyImportAccumulator.getConsolidatedImportKeyResult()); + +            stopSelf();//we're done here +        } +    } + +    private void keyImportFailed(ImportKeyResult result) { +        sendMessageToHandler(ServiceProgressHandler.MessageStatus.OKAY, result); +    } + +    private void sendMessageToHandler(ServiceProgressHandler.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.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(ServiceProgressHandler.MessageStatus status, OperationResult data) { +        Bundle bundle = new Bundle(); +        bundle.putParcelable(OperationResult.EXTRA_RESULT, data); +        sendMessageToHandler(status, null, bundle); +    } + +    private void sendMessageToHandler(ServiceProgressHandler.MessageStatus status, Bundle data) { +        sendMessageToHandler(status, null, data); +    } + +    private void sendMessageToHandler(ServiceProgressHandler.MessageStatus status) { +        sendMessageToHandler(status, null, null); +    } + +    /** +     * Set progress of ProgressDialog by sending message to handler on UI thread +     */ +    @Override +    public synchronized 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(ServiceProgressHandler.MessageStatus.UPDATE_PROGRESS, null, data); +    } + +    @Override +    public synchronized void setProgress(int resourceId, int progress, int max) { +        setProgress(getString(resourceId), progress, max); +    } + +    @Override +    public synchronized void setProgress(int progress, int max) { +        setProgress(null, progress, max); +    } + +    @Override +    public synchronized void setPreventCancel() { +        sendMessageToHandler(ServiceProgressHandler.MessageStatus.PREVENT_CANCEL); +    } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index d5f13f7ce..5ecfb29f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -60,7 +60,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;  import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;  import org.sufficientlysecure.keychain.util.FileHelper;  import org.sufficientlysecure.keychain.util.InputData;  import org.sufficientlysecure.keychain.util.Log; @@ -136,7 +136,7 @@ public class KeychainIntentService extends IntentService implements Progressable          private static final IOType[] values = values();          public static IOType fromInt(int n) { -            if(n < 0 || n >= values.length) { +            if (n < 0 || n >= values.length) {                  return UNKNOWN;              } else {                  return values[n]; @@ -395,12 +395,12 @@ public class KeychainIntentService extends IntentService implements Progressable                      }                      Bundle resultData = new Bundle(); -                    resultData.putString(KeychainIntentServiceHandler.DATA_MESSAGE, "OK"); +                    resultData.putString(ServiceProgressHandler.DATA_MESSAGE, "OK");                      // these help the handler construct a useful human-readable message -                    resultData.putString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL, prover.getProofUrl()); -                    resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl()); -                    resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL, prover.getPresenceLabel()); +                    resultData.putString(ServiceProgressHandler.KEYBASE_PROOF_URL, prover.getProofUrl()); +                    resultData.putString(ServiceProgressHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl()); +                    resultData.putString(ServiceProgressHandler.KEYBASE_PRESENCE_LABEL, prover.getPresenceLabel());                      sendMessageToHandler(MessageStatus.OKAY, resultData);                  } catch (Exception e) {                      sendErrorToHandler(e); @@ -596,7 +596,7 @@ public class KeychainIntentService extends IntentService implements Progressable      private void sendProofError(String msg) {          Bundle bundle = new Bundle(); -        bundle.putString(KeychainIntentServiceHandler.DATA_ERROR, msg); +        bundle.putString(ServiceProgressHandler.DATA_ERROR, msg);          sendMessageToHandler(MessageStatus.OKAY, bundle);      } @@ -613,7 +613,7 @@ public class KeychainIntentService extends IntentService implements Progressable          Log.d(Constants.TAG, "KeychainIntentService Exception: ", e);          Bundle data = new Bundle(); -        data.putString(KeychainIntentServiceHandler.DATA_ERROR, message); +        data.putString(ServiceProgressHandler.DATA_ERROR, message);          sendMessageToHandler(MessageStatus.EXCEPTION, null, data);      } @@ -661,10 +661,10 @@ public class KeychainIntentService extends IntentService implements Progressable          Bundle data = new Bundle();          if (message != null) { -            data.putString(KeychainIntentServiceHandler.DATA_MESSAGE, message); +            data.putString(ServiceProgressHandler.DATA_MESSAGE, message);          } -        data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS, progress); -        data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX, max); +        data.putInt(ServiceProgressHandler.DATA_PROGRESS, progress); +        data.putInt(ServiceProgressHandler.DATA_PROGRESS_MAX, max);          sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, null, data);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index ee481ad31..93a2bee23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -93,7 +93,6 @@ public class PassphraseCacheService extends Service {      public static final String EXTRA_MESSENGER = "messenger";      public static final String EXTRA_USER_ID = "user_id"; -    private static final int REQUEST_ID = 0;      private static final long DEFAULT_TTL = 15;      private static final int NOTIFICATION_ID = 1; @@ -314,7 +313,8 @@ public class PassphraseCacheService extends Service {      private static PendingIntent buildIntent(Context context, long keyId) {          Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);          intent.putExtra(EXTRA_KEY_ID, keyId); -        return PendingIntent.getBroadcast(context, REQUEST_ID, intent, +        // request code should be unique for each PendingIntent, thus keyId is used +        return PendingIntent.getBroadcast(context, (int) keyId, intent,                  PendingIntent.FLAG_CANCEL_CURRENT);      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java index bd047518d..4bd3481e6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java @@ -30,7 +30,7 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.Log; -public class KeychainIntentServiceHandler extends Handler { +public class ServiceProgressHandler extends Handler {      // possible messages sent from this service to handler on ui      public static enum MessageStatus{ @@ -67,28 +67,34 @@ public class KeychainIntentServiceHandler extends Handler {      Activity mActivity;      ProgressDialogFragment mProgressDialogFragment; -    public KeychainIntentServiceHandler(Activity activity) { +    public ServiceProgressHandler(Activity activity) {          this.mActivity = activity;      } -    public KeychainIntentServiceHandler(Activity activity, -                                        ProgressDialogFragment progressDialogFragment) { +    public ServiceProgressHandler(Activity activity, +                                  ProgressDialogFragment progressDialogFragment) {          this.mActivity = activity;          this.mProgressDialogFragment = progressDialogFragment;      } -    public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, -                                        int progressDialogStyle) { -        this(activity, progressDialogMessage, progressDialogStyle, false); +    public ServiceProgressHandler(Activity activity, +                                  String progressDialogMessage, +                                  int progressDialogStyle, +                                  ProgressDialogFragment.ServiceType serviceType) { +        this(activity, progressDialogMessage, progressDialogStyle, false, serviceType);      } -    public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, -                                        int progressDialogStyle, boolean cancelable) { +    public ServiceProgressHandler(Activity activity, +                                  String progressDialogMessage, +                                  int progressDialogStyle, +                                  boolean cancelable, +                                  ProgressDialogFragment.ServiceType serviceType) {          this.mActivity = activity;          this.mProgressDialogFragment = ProgressDialogFragment.newInstance(                  progressDialogMessage,                  progressDialogStyle, -                cancelable); +                cancelable, +                serviceType);      }      public void showProgressDialog(FragmentActivity activity) { @@ -129,9 +135,9 @@ public class KeychainIntentServiceHandler extends Handler {                  // show error from service                  if (data.containsKey(DATA_ERROR)) { -                    Notify.showNotify(mActivity, +                    Notify.create(mActivity,                              mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)), -                            Notify.Style.ERROR); +                            Notify.Style.ERROR).show();                  }                  break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index a0f89b06a..9b6e8d8f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -55,9 +55,10 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.CertifyActionsParcel;  import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;  import org.sufficientlysecure.keychain.ui.widget.KeySpinner; @@ -169,8 +170,8 @@ public class CertifyKeyFragment extends LoaderFragment              @Override              public void onClick(View v) {                  if (mSignMasterKeyId == Constants.key.none) { -                    Notify.showNotify(getActivity(), getString(R.string.select_key_to_certify), -                            Notify.Style.ERROR); +                    Notify.create(getActivity(), getString(R.string.select_key_to_certify), +                            Notify.Style.ERROR).show();                  } else {                      initiateCertifying();                  } @@ -360,8 +361,8 @@ public class CertifyKeyFragment extends LoaderFragment          // Bail out if there is not at least one user id selected          ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();          if (certifyActions.isEmpty()) { -            Notify.showNotify(getActivity(), "No identities selected!", -                    Notify.Style.ERROR); +            Notify.create(getActivity(), "No identities selected!", +                    Notify.Style.ERROR).show();              return;          } @@ -388,8 +389,12 @@ public class CertifyKeyFragment extends LoaderFragment          } else {              // Message is received after signing is done in KeychainIntentService -            KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), -                    getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) { +            ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                    getActivity(), +                    getString(R.string.progress_certifying), +                    ProgressDialog.STYLE_SPINNER, +                    true, +                    ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {                  public void handleMessage(Message message) {                      // handle messages by standard KeychainIntentServiceHandler first                      super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java index c55aad1f9..11ba3e287 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java @@ -26,7 +26,8 @@ import android.support.v4.app.FragmentActivity;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  /**   * We can not directly create a dialog on the application context. @@ -49,10 +50,11 @@ public class ConsolidateDialogActivity extends FragmentActivity {      private void consolidateRecovery(boolean recovery) {          // Message is received after importing is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(                  this,                  getString(R.string.progress_importing), -                ProgressDialog.STYLE_HORIZONTAL) { +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 75f49a426..b0a13c897 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -39,16 +39,15 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;  import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;  import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Passphrase;  import org.sufficientlysecure.keychain.util.Preferences; -import java.util.ArrayList;  import java.util.Iterator;  public class CreateKeyFinalFragment extends Fragment { @@ -195,10 +194,11 @@ public class CreateKeyFinalFragment extends Fragment {          Intent intent = new Intent(getActivity(), KeychainIntentService.class);          intent.setAction(KeychainIntentService.ACTION_EDIT_KEYRING); -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(                  getActivity(),                  getString(R.string.progress_building_key), -                ProgressDialog.STYLE_HORIZONTAL) { +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -267,8 +267,11 @@ public class CreateKeyFinalFragment extends Fragment {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data); -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), -                getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_uploading), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -277,8 +280,8 @@ public class CreateKeyFinalFragment extends Fragment {                      // TODO: upload operation needs a result!                      // TODO: then combine these results                      //if (result.getResult() == OperationResultParcel.RESULT_OK) { -                    //Notify.showNotify(getActivity(), R.string.key_send_success, -                    //Notify.Style.INFO); +                    //Notify.create(getActivity(), R.string.key_send_success, +                    //Notify.Style.OK).show();                      Intent data = new Intent();                      data.putExtra(OperationResult.EXTRA_RESULT, saveKeyResult); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 71832daa5..c75e28145 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -38,8 +38,9 @@ import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;  import org.sufficientlysecure.keychain.service.KeychainIntentService;  import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.FileHelper;  import org.sufficientlysecure.keychain.util.Log; @@ -139,7 +140,7 @@ public class DecryptFilesFragment extends DecryptFragment {      private void decryptAction() {          if (mInputUri == null) { -            Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR).show();              return;          } @@ -197,8 +198,11 @@ public class DecryptFilesFragment extends DecryptFragment {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after decrypting is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), -                getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_decrypting), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -271,8 +275,11 @@ public class DecryptFilesFragment extends DecryptFragment {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after decrypting is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), -                getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_decrypting), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index 1e9e7bcb1..bc2ec014a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -161,7 +161,7 @@ public class DecryptTextActivity extends BaseActivity {                  if (sharedText != null) {                      loadFragment(savedInstanceState, sharedText);                  } else { -                    Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); +                    Notify.create(this, R.string.error_invalid_data, Notify.Style.ERROR).show();                  }              } else {                  Log.e(Constants.TAG, "ACTION_SEND received non-plaintext, this should not happen in this activity!"); @@ -175,7 +175,7 @@ public class DecryptTextActivity extends BaseActivity {              if (extraText != null) {                  loadFragment(savedInstanceState, extraText);              } else { -                Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); +                Notify.create(this, R.string.error_invalid_data, Notify.Style.ERROR).show();              }          } else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) {              Log.d(Constants.TAG, "ACTION_DECRYPT_FROM_CLIPBOARD"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 30cf739fc..f6e21937d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -37,7 +37,8 @@ import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;  import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;  import org.sufficientlysecure.keychain.service.KeychainIntentService;  import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.ShareHelper; @@ -132,7 +133,7 @@ public class DecryptTextFragment extends DecryptFragment {      private void copyToClipboard(String text) {          ClipboardReflection.copyToClipboard(getActivity(), text); -        Notify.showNotify(getActivity(), R.string.text_copied_to_clipboard, Notify.Style.INFO); +        Notify.create(getActivity(), R.string.text_copied_to_clipboard, Notify.Style.OK).show();      }      @Override @@ -167,8 +168,11 @@ public class DecryptTextFragment extends DecryptFragment {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after encrypting is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), -                getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_decrypting), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index d2c1ab74c..417b50b50 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -50,7 +50,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;  import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel;  import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; @@ -59,12 +59,7 @@ import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;  import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;  import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;  import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter; -import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyExpiryDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.*;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Passphrase; @@ -577,11 +572,11 @@ public class EditKeyFragment extends LoaderFragment implements      private void returnKeyringParcel() {          if (mSaveKeyringParcel.mAddUserIds.size() == 0) { -            Notify.showNotify(getActivity(), R.string.edit_key_error_add_identity, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.edit_key_error_add_identity, Notify.Style.ERROR).show();              return;          }          if (mSaveKeyringParcel.mAddSubKeys.size() == 0) { -            Notify.showNotify(getActivity(), R.string.edit_key_error_add_subkey, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.edit_key_error_add_subkey, Notify.Style.ERROR).show();              return;          } @@ -597,11 +592,12 @@ public class EditKeyFragment extends LoaderFragment implements      private void saveInDatabase(Passphrase passphrase) {          Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString()); -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(                  getActivity(),                  getString(R.string.progress_saving),                  ProgressDialog.STYLE_HORIZONTAL, -                true) { +                true, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 5438f667c..cd1028de4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -31,7 +31,8 @@ import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;  import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;  import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.util.Passphrase;  import java.util.Date; @@ -123,8 +124,11 @@ public abstract class EncryptActivity extends BaseActivity {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after encrypting is done in KeychainIntentService -        KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler(this, -                getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler serviceHandler = new ServiceProgressHandler( +                this, +                getString(R.string.progress_encrypting), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 0dd672c90..fe9b05226 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -303,7 +303,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi          // file checks          if (mInputUris.isEmpty()) { -            Notify.showNotify(this, R.string.no_file_selected, Notify.Style.ERROR); +            Notify.create(this, R.string.no_file_selected, Notify.Style.ERROR) +                    .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment));              return false;          } else if (mInputUris.size() > 1 && !mShareAfterEncrypt) {              // This should be impossible... @@ -317,11 +318,13 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi              // symmetric encryption checks              if (mPassphrase == null) { -                Notify.showNotify(this, R.string.passphrases_do_not_match, Notify.Style.ERROR); +                Notify.create(this, R.string.passphrases_do_not_match, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment));                  return false;              }              if (mPassphrase.isEmpty()) { -                Notify.showNotify(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR); +                Notify.create(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment));                  return false;              } @@ -333,7 +336,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi              // Files must be encrypted, only text can be signed-only right now              if (!gotEncryptionKeys) { -                Notify.showNotify(this, R.string.select_encryption_key, Notify.Style.ERROR); +                Notify.create(this, R.string.select_encryption_key, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment));                  return false;              }          } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 9c9b44511..4ba76d8ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -115,9 +115,9 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt          }          if (mEncryptInterface.getInputUris().contains(inputUri)) { -            Notify.showNotify(getActivity(), +            Notify.create(getActivity(),                      getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), -                    Notify.Style.ERROR); +                    Notify.Style.ERROR).show(this);              return;          } @@ -153,7 +153,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt      private void encryptClicked(boolean share) {          if (mEncryptInterface.getInputUris().isEmpty()) { -            Notify.showNotify(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR).show(this);              return;          }          if (share) { @@ -169,7 +169,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt              mEncryptInterface.startEncrypt(true);          } else {              if (mEncryptInterface.getInputUris().size() > 1) { -                Notify.showNotify(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR); +                Notify.create(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR).show(this);                  return;              }              showOutputFileDialog(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 847f745d7..dd09e62c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -136,7 +136,9 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv      @Override      public void setPassphrase(Passphrase passphrase) { -        mPassphrase.removeFromMemory(); +        if (mPassphrase != null) { +            mPassphrase.removeFromMemory(); +        }          mPassphrase = passphrase;      } @@ -198,8 +200,9 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv              // Copy to clipboard              copyToClipboard(result.getResultBytes());              result.createNotify(EncryptTextActivity.this).show(); -            // Notify.showNotify(EncryptTextActivity.this, -            // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO); +            // Notify.create(EncryptTextActivity.this, +            // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK) +            // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));          }      } @@ -281,7 +284,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv      protected boolean inputIsValid() {          if (mMessage == null) { -            Notify.showNotify(this, R.string.error_message, Notify.Style.ERROR); +            Notify.create(this, R.string.error_message, Notify.Style.ERROR) +                    .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));              return false;          } @@ -289,11 +293,13 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv              // symmetric encryption checks              if (mPassphrase == null) { -                Notify.showNotify(this, R.string.passphrases_do_not_match, Notify.Style.ERROR); +                Notify.create(this, R.string.passphrases_do_not_match, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));                  return false;              }              if (mPassphrase.isEmpty()) { -                Notify.showNotify(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR); +                Notify.create(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));                  return false;              } @@ -304,7 +310,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv                      && mEncryptionKeyIds.length > 0);              if (!gotEncryptionKeys && mSigningKeyId == 0) { -                Notify.showNotify(this, R.string.select_encryption_or_signature_key, Notify.Style.ERROR); +                Notify.create(this, R.string.select_encryption_or_signature_key, Notify.Style.ERROR) +                        .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));                  return false;              }          } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java index 5909970af..912caf32f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java @@ -27,11 +27,14 @@ import android.view.View;  import android.view.ViewGroup;  import android.widget.TextView; +import org.markdown4j.Markdown4jProcessor;  import org.sufficientlysecure.htmltextview.HtmlTextView;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.util.Log; +import java.io.IOException; +  public class HelpAboutFragment extends Fragment { @@ -44,8 +47,14 @@ public class HelpAboutFragment extends Fragment {          HtmlTextView aboutTextView = (HtmlTextView) view.findViewById(R.id.help_about_text); -        // load html from raw resource (Parsing handled by HtmlTextView library) -        aboutTextView.setHtmlFromRawResource(getActivity(), R.raw.help_about, true); +        // load mardown from raw resource +        try { +            String html = new Markdown4jProcessor().process( +                    getActivity().getResources().openRawResource(R.raw.help_about)); +            aboutTextView.setHtmlFromString(html, true); +        } catch (IOException e) { +            Log.e(Constants.TAG, "IOException", e); +        }          // no flickering when clicking textview for Android < 4          aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index cd6cdf4d6..24136a4b8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -64,18 +64,23 @@ public class HelpActivity extends BaseActivity {          }          Bundle startBundle = new Bundle(); -        startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); -        mTabsAdapter.addTab(HelpHtmlFragment.class, startBundle, +        startBundle.putInt(HelpMarkdownFragment.ARG_MARKDOWN_FILE, R.raw.help_start); +        mTabsAdapter.addTab(HelpMarkdownFragment.class, startBundle,                  getString(R.string.help_tab_start)); -        Bundle wotBundle = new Bundle(); -        wotBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_certification); -        mTabsAdapter.addTab(HelpHtmlFragment.class, wotBundle, +        Bundle certificationBundle = new Bundle(); +        certificationBundle.putInt(HelpMarkdownFragment.ARG_MARKDOWN_FILE, R.raw.help_certification); +        mTabsAdapter.addTab(HelpMarkdownFragment.class, certificationBundle,                  getString(R.string.help_tab_wot)); +        Bundle faqBundle = new Bundle(); +        faqBundle.putInt(HelpMarkdownFragment.ARG_MARKDOWN_FILE, R.raw.help_faq); +        mTabsAdapter.addTab(HelpMarkdownFragment.class, faqBundle, +                getString(R.string.help_tab_faq)); +          Bundle changelogBundle = new Bundle(); -        changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); -        mTabsAdapter.addTab(HelpHtmlFragment.class, changelogBundle, +        changelogBundle.putInt(HelpMarkdownFragment.ARG_MARKDOWN_FILE, R.raw.help_changelog); +        mTabsAdapter.addTab(HelpMarkdownFragment.class, changelogBundle,                  getString(R.string.help_tab_changelog));          mTabsAdapter.addTab(HelpAboutFragment.class, null, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java index a3f0ef614..69ddf2e99 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java @@ -26,24 +26,29 @@ import android.view.View;  import android.view.ViewGroup;  import android.widget.ScrollView; +import org.markdown4j.Markdown4jProcessor;  import org.sufficientlysecure.htmltextview.HtmlTextView; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; -public class HelpHtmlFragment extends Fragment { +import java.io.IOException; + +public class HelpMarkdownFragment extends Fragment {      private Activity mActivity;      private int mHtmlFile; -    public static final String ARG_HTML_FILE = "htmlFile"; +    public static final String ARG_MARKDOWN_FILE = "htmlFile";      /**       * Create a new instance of HelpHtmlFragment, providing "htmlFile" as an argument.       */ -    static HelpHtmlFragment newInstance(int htmlFile) { -        HelpHtmlFragment f = new HelpHtmlFragment(); +    static HelpMarkdownFragment newInstance(int htmlFile) { +        HelpMarkdownFragment f = new HelpMarkdownFragment();          // Supply html raw file input as an argument.          Bundle args = new Bundle(); -        args.putInt(ARG_HTML_FILE, htmlFile); +        args.putInt(ARG_MARKDOWN_FILE, htmlFile);          f.setArguments(args);          return f; @@ -53,7 +58,7 @@ public class HelpHtmlFragment extends Fragment {      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          mActivity = getActivity(); -        mHtmlFile = getArguments().getInt(ARG_HTML_FILE); +        mHtmlFile = getArguments().getInt(ARG_MARKDOWN_FILE);          ScrollView scroller = new ScrollView(mActivity);          HtmlTextView text = new HtmlTextView(mActivity); @@ -65,8 +70,13 @@ public class HelpHtmlFragment extends Fragment {          scroller.addView(text); -        // load html from raw resource (Parsing handled by HtmlTextView library) -        text.setHtmlFromRawResource(getActivity(), mHtmlFile, true); +        // load mardown from raw resource +        try { +            String html = new Markdown4jProcessor().process(getActivity().getResources().openRawResource(mHtmlFile)); +            text.setHtmlFromString(html, true); +        } catch (IOException e) { +            Log.e(Constants.TAG, "IOException", e); +        }          // no flickering when clicking textview for Android < 4          text.setTextColor(getResources().getColor(android.R.color.black)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index d51e2c7fc..dc4a2eb10 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -26,6 +26,7 @@ import android.os.Messenger;  import android.support.v4.app.Fragment;  import android.view.View;  import android.view.View.OnClickListener; +import android.view.ViewGroup;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; @@ -34,8 +35,9 @@ import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;  import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;  import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;  import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.CloudImportService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.Log; @@ -277,7 +279,8 @@ public class ImportKeysActivity extends BaseActivity {      private boolean isFingerprintValid(String fingerprint) {          if (fingerprint == null || fingerprint.length() < 40) { -            Notify.showNotify(this, R.string.import_qr_code_too_short_fingerprint, Notify.Style.ERROR); +            Notify.create(this, R.string.import_qr_code_too_short_fingerprint, Notify.Style.ERROR) +                    .show((ViewGroup) findViewById(R.id.import_snackbar));              return false;          } else {              return true; @@ -292,12 +295,13 @@ public class ImportKeysActivity extends BaseActivity {       * Import keys with mImportData       */      public void importKeys() { -        // Message is received after importing is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +        // Message is received after importing is done in CloudImportService +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(                  this,                  getString(R.string.progress_importing),                  ProgressDialog.STYLE_HORIZONTAL, -                true) { +                true, +                ProgressDialogFragment.ServiceType.CLOUD_IMPORT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -329,7 +333,8 @@ public class ImportKeysActivity extends BaseActivity {                          return;                      } -                    result.createNotify(ImportKeysActivity.this).show(); +                    result.createNotify(ImportKeysActivity.this) +                            .show((ViewGroup) findViewById(R.id.import_snackbar));                  }              }          }; @@ -339,9 +344,7 @@ public class ImportKeysActivity extends BaseActivity {              Log.d(Constants.TAG, "importKeys started");              // Send all information needed to service to import key in other thread -            Intent intent = new Intent(this, KeychainIntentService.class); - -            intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); +            Intent intent = new Intent(this, CloudImportService.class);              // fill values for this action              Bundle data = new Bundle(); @@ -359,11 +362,11 @@ public class ImportKeysActivity extends BaseActivity {                          new ParcelableFileCache<>(this, "key_import.pcl");                  cache.writeCache(selectedEntries); -                intent.putExtra(KeychainIntentService.EXTRA_DATA, data); +                intent.putExtra(CloudImportService.EXTRA_DATA, data);                  // Create a new Messenger for the communication back                  Messenger messenger = new Messenger(saveHandler); -                intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); +                intent.putExtra(CloudImportService.EXTRA_MESSENGER, messenger);                  // show progress dialog                  saveHandler.showProgressDialog(this); @@ -372,20 +375,19 @@ public class ImportKeysActivity extends BaseActivity {                  startService(intent);              } catch (IOException e) {                  Log.e(Constants.TAG, "Problem writing cache file", e); -                Notify.showNotify(this, "Problem writing cache file!", Notify.Style.ERROR); +                Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR) +                        .show((ViewGroup) findViewById(R.id.import_snackbar));              }          } else if (ls instanceof ImportKeysListFragment.CloudLoaderState) {              ImportKeysListFragment.CloudLoaderState sls = (ImportKeysListFragment.CloudLoaderState) ls;              // Send all information needed to service to query keys in other thread -            Intent intent = new Intent(this, KeychainIntentService.class); - -            intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); +            Intent intent = new Intent(this, CloudImportService.class);              // fill values for this action              Bundle data = new Bundle(); -            data.putString(KeychainIntentService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver); +            data.putString(CloudImportService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver);              // get selected key entries              ArrayList<ParcelableKeyRing> keys = new ArrayList<>(); @@ -398,13 +400,13 @@ public class ImportKeysActivity extends BaseActivity {                      );                  }              } -            data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keys); +            data.putParcelableArrayList(CloudImportService.IMPORT_KEY_LIST, keys); -            intent.putExtra(KeychainIntentService.EXTRA_DATA, data); +            intent.putExtra(CloudImportService.EXTRA_DATA, data);              // Create a new Messenger for the communication back              Messenger messenger = new Messenger(saveHandler); -            intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); +            intent.putExtra(CloudImportService.EXTRA_MESSENGER, messenger);              // show progress dialog              saveHandler.showProgressDialog(this); @@ -412,7 +414,8 @@ public class ImportKeysActivity extends BaseActivity {              // start service with intent              startService(intent);          } else { -            Notify.showNotify(this, R.string.error_nothing_import, Notify.Style.ERROR); +            Notify.create(this, R.string.error_nothing_import, Notify.Style.ERROR) +                    .show((ViewGroup) findViewById(R.id.import_snackbar));          }      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index 1c1e5fe99..21747f77b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -42,7 +42,8 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;  import org.sufficientlysecure.keychain.operations.results.OperationResult;  import org.sufficientlysecure.keychain.operations.results.SingletonResult;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Preferences; @@ -213,11 +214,12 @@ public class ImportKeysProxyActivity extends FragmentActivity {      private void startImportService (ArrayList<ParcelableKeyRing> keyRings) {          // Message is received after importing is done in KeychainIntentService -        KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler( +        ServiceProgressHandler serviceHandler = new ServiceProgressHandler(                  this,                  getString(R.string.progress_importing),                  ProgressDialog.STYLE_HORIZONTAL, -                true) { +                true, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index f8939f3d1..861ae12d9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -58,16 +58,21 @@ import com.getbase.floatingactionbutton.FloatingActionsMenu;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;  import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;  import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;  import org.sufficientlysecure.keychain.operations.results.OperationResult;  import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;  import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.CloudImportService;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Highlighter;  import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;  import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; @@ -78,6 +83,7 @@ import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Preferences;  import java.io.IOException; +import java.util.ArrayList;  import java.util.HashMap;  import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; @@ -169,6 +175,22 @@ public class KeyListFragment extends LoaderFragment          mStickyList.setDrawingListUnderStickyHeader(false);          mStickyList.setFastScrollEnabled(true); +        // Adds an empty footer view so that the Floating Action Button won't block content +        // in last few rows. +        View footer = new View(getActivity()); + +        int spacing = (int) android.util.TypedValue.applyDimension( +                android.util.TypedValue.COMPLEX_UNIT_DIP, 72, getResources().getDisplayMetrics() +        ); + +        android.widget.AbsListView.LayoutParams params = new android.widget.AbsListView.LayoutParams( +                android.widget.AbsListView.LayoutParams.MATCH_PARENT, +                spacing +        ); + +        footer.setLayoutParams(params); +        mStickyList.addFooterView(footer, null, false); +          /*           * Multi-selection           */ @@ -369,13 +391,13 @@ public class KeyListFragment extends LoaderFragment      /**       * Show dialog to delete key       * -     * @param hasSecret    must contain whether the list of masterKeyIds contains a secret key or not +     * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not       */      public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {          // Can only work on singular secret keys          if (hasSecret && masterKeyIds.length > 1) { -            Notify.showNotify(getActivity(), R.string.secret_cannot_multiple, -                    Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.secret_cannot_multiple, +                    Notify.Style.ERROR).show();              return;          } @@ -461,6 +483,10 @@ public class KeyListFragment extends LoaderFragment                  mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);                  return true; +            case R.id.menu_key_list_update_all_keys: +                updateAllKeys(); +                return true; +              case R.id.menu_key_list_debug_cons:                  consolidate();                  return true; @@ -468,21 +494,21 @@ public class KeyListFragment extends LoaderFragment              case R.id.menu_key_list_debug_read:                  try {                      KeychainDatabase.debugBackup(getActivity(), true); -                    Notify.showNotify(getActivity(), "Restored debug_backup.db", Notify.Style.INFO); +                    Notify.create(getActivity(), "Restored debug_backup.db", Notify.Style.OK).show();                      getActivity().getContentResolver().notifyChange(KeychainContract.KeyRings.CONTENT_URI, null);                  } catch (IOException e) {                      Log.e(Constants.TAG, "IO Error", e); -                    Notify.showNotify(getActivity(), "IO Error " + e.getMessage(), Notify.Style.ERROR); +                    Notify.create(getActivity(), "IO Error " + e.getMessage(), Notify.Style.ERROR).show();                  }                  return true;              case R.id.menu_key_list_debug_write:                  try {                      KeychainDatabase.debugBackup(getActivity(), false); -                    Notify.showNotify(getActivity(), "Backup to debug_backup.db completed", Notify.Style.INFO); +                    Notify.create(getActivity(), "Backup to debug_backup.db completed", Notify.Style.OK).show();                  } catch (IOException e) {                      Log.e(Constants.TAG, "IO Error", e); -                    Notify.showNotify(getActivity(), "IO Error: " + e.getMessage(), Notify.Style.ERROR); +                    Notify.create(getActivity(), "IO Error: " + e.getMessage(), Notify.Style.ERROR).show();                  }                  return true; @@ -545,12 +571,90 @@ public class KeyListFragment extends LoaderFragment          startActivityForResult(intent, 0);      } +    private void updateAllKeys() { +        Context context = getActivity(); + +        ProviderHelper providerHelper = new ProviderHelper(context); + +        Cursor cursor = providerHelper.getContentResolver().query( +                KeyRings.buildUnifiedKeyRingsUri(), new String[]{ +                        KeyRings.FINGERPRINT +                }, null, null, null +        ); + +        ArrayList<ParcelableKeyRing> keyList = new ArrayList<>(); + +        while (cursor.moveToNext()) { +            byte[] blob = cursor.getBlob(0);//fingerprint column is 0 +            String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); +            ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); +            keyList.add(keyEntry); +        } + +        ServiceProgressHandler serviceHandler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_updating), +                ProgressDialog.STYLE_HORIZONTAL, +                true, +                ProgressDialogFragment.ServiceType.CLOUD_IMPORT) { +            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 ImportKeyResult result = +                            returnData.getParcelable(OperationResult.EXTRA_RESULT); +                    if (result == null) { +                        Log.e(Constants.TAG, "result == null"); +                        return; +                    } + +                    result.createNotify(getActivity()).show(); +                } +            } +        }; + +        // Send all information needed to service to query keys in other thread +        Intent intent = new Intent(getActivity(), CloudImportService.class); + +        // fill values for this action +        Bundle data = new Bundle(); + +        // search config +        { +            Preferences prefs = Preferences.getPreferences(getActivity()); +            Preferences.CloudSearchPrefs cloudPrefs = +                    new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); +            data.putString(CloudImportService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); +        } + +        data.putParcelableArrayList(CloudImportService.IMPORT_KEY_LIST, keyList); + +        intent.putExtra(CloudImportService.EXTRA_DATA, data); + +        // Create a new Messenger for the communication back +        Messenger messenger = new Messenger(serviceHandler); +        intent.putExtra(CloudImportService.EXTRA_MESSENGER, messenger); + +        // show progress dialog +        serviceHandler.showProgressDialog(getActivity()); + +        // start service with intent +        getActivity().startService(intent); +    } +      private void consolidate() {          // Message is received after importing is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(                  getActivity(),                  getString(R.string.progress_importing), -                ProgressDialog.STYLE_HORIZONTAL) { +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -909,5 +1013,4 @@ public class KeyListFragment extends LoaderFragment      } -  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index d3c1d971a..43af07bbe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -80,7 +80,7 @@ public class QrCodeViewActivity extends BaseActivity {                      KeychainContract.KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);              if (blob == null) {                  Log.e(Constants.TAG, "key not found!"); -                Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR); +                Notify.create(this, R.string.error_key_not_found, Style.ERROR).show();                  ActivityCompat.finishAfterTransition(QrCodeViewActivity.this);              } @@ -102,7 +102,7 @@ public class QrCodeViewActivity extends BaseActivity {                      });          } catch (ProviderHelper.NotFoundException e) {              Log.e(Constants.TAG, "key not found!", e); -            Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR); +            Notify.create(this, R.string.error_key_not_found, Style.ERROR).show();              ActivityCompat.finishAfterTransition(QrCodeViewActivity.this);          }      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index d0cea5f05..c58a945d3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -39,7 +39,8 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.ParcelableFileCache; @@ -123,11 +124,12 @@ public class SafeSlingerActivity extends BaseActivity {              final FragmentActivity activity = SafeSlingerActivity.this;              // Message is received after importing is done in KeychainIntentService -            KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( +            ServiceProgressHandler saveHandler = new ServiceProgressHandler(                      activity,                      getString(R.string.progress_importing),                      ProgressDialog.STYLE_HORIZONTAL, -                    true) { +                    true, +                    ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {                  public void handleMessage(Message message) {                      // handle messages by standard KeychainIntentServiceHandler first                      super.handleMessage(message); @@ -205,7 +207,7 @@ public class SafeSlingerActivity extends BaseActivity {                  activity.startService(intent);              } catch (IOException e) {                  Log.e(Constants.TAG, "Problem writing cache file", e); -                Notify.showNotify(activity, "Problem writing cache file!", Notify.Style.ERROR); +                Notify.create(activity, "Problem writing cache file!", Notify.Style.ERROR).show();              }          } else {              // give everything else down to KeyListActivity! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 4fb2074a5..c518cbcdb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -36,7 +36,8 @@ import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Preferences; @@ -107,8 +108,11 @@ public class UploadKeyActivity extends BaseActivity {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after uploading is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, -                getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                this, +                getString(R.string.progress_uploading), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 5834fa502..0c2d8693f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,18 +21,12 @@ package org.sufficientlysecure.keychain.ui;  import android.animation.ArgbEvaluator;  import android.animation.ObjectAnimator;  import android.annotation.SuppressLint; -import android.annotation.TargetApi;  import android.app.Activity;  import android.app.ActivityOptions;  import android.content.Intent; -import android.content.pm.PackageManager;  import android.database.Cursor;  import android.graphics.Bitmap;  import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcEvent;  import android.os.AsyncTask;  import android.os.Build;  import android.os.Bundle; @@ -40,7 +34,6 @@ import android.os.Handler;  import android.os.Message;  import android.os.Messenger;  import android.provider.ContactsContract; -import android.provider.Settings;  import android.support.v4.app.ActivityCompat;  import android.support.v4.app.LoaderManager;  import android.support.v4.content.CursorLoader; @@ -58,9 +51,7 @@ import android.widget.ImageView;  import android.widget.RelativeLayout;  import android.widget.TextView;  import android.widget.Toast; -  import com.getbase.floatingactionbutton.FloatingActionButton; -  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; @@ -72,8 +63,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;  import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;  import org.sufficientlysecure.keychain.ui.util.FormattingUtils; @@ -84,6 +75,7 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;  import org.sufficientlysecure.keychain.util.ContactHelper;  import org.sufficientlysecure.keychain.util.ExportHelper;  import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.NfcHelper;  import org.sufficientlysecure.keychain.util.Preferences;  import java.util.ArrayList; @@ -93,8 +85,8 @@ public class ViewKeyActivity extends BaseActivity implements          LoaderManager.LoaderCallbacks<Cursor> {      static final int REQUEST_QR_FINGERPRINT = 1; -    static final int REQUEST_DELETE= 2; -    static final int REQUEST_EXPORT= 3; +    static final int REQUEST_DELETE = 2; +    static final int REQUEST_EXPORT = 3;      ExportHelper mExportHelper;      ProviderHelper mProviderHelper; @@ -115,11 +107,7 @@ public class ViewKeyActivity extends BaseActivity implements      private CardView mQrCodeLayout;      // NFC -    private NfcAdapter mNfcAdapter; -    private NfcAdapter.CreateNdefMessageCallback mNdefCallback; -    private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback; -    private byte[] mNfcKeyringBytes; -    private static final int NFC_SENT = 1; +    private NfcHelper mNfcHelper;      private static final int LOADER_ID_UNIFIED = 0; @@ -256,7 +244,7 @@ public class ViewKeyActivity extends BaseActivity implements          mActionNfc.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) { -                invokeNfcBeam(); +                mNfcHelper.invokeNfcBeam();              }          }); @@ -264,7 +252,8 @@ public class ViewKeyActivity extends BaseActivity implements          // or start new ones.          getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); -        initNfc(mDataUri); +        mNfcHelper = new NfcHelper(this, mProviderHelper); +        mNfcHelper.initNfc(mDataUri);          startFragment(savedInstanceState, mDataUri);      } @@ -349,7 +338,7 @@ public class ViewKeyActivity extends BaseActivity implements                  try {                      updateFromKeyserver(mDataUri, mProviderHelper);                  } catch (ProviderHelper.NotFoundException e) { -                    Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); +                    Notify.create(this, R.string.error_key_not_found, Notify.Style.ERROR).show();                  }                  return true;              } @@ -375,41 +364,6 @@ public class ViewKeyActivity extends BaseActivity implements          return true;      } -    @TargetApi(Build.VERSION_CODES.LOLLIPOP) -    private void invokeNfcBeam() { -        // Check if device supports NFC -        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { -            Notify.createNotify(this, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show(); -            return; -        } -        // Check for available NFC Adapter -        mNfcAdapter = NfcAdapter.getDefaultAdapter(this); -        if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { -            Notify.createNotify(this, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { -                @Override -                public void onAction() { -                    Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS); -                    startActivity(intentSettings); -                } -            }, R.string.menu_nfc_preferences).show(); - -            return; -        } - -        if (!mNfcAdapter.isNdefPushEnabled()) { -            Notify.createNotify(this, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { -                @Override -                public void onAction() { -                    Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); -                    startActivity(intentSettings); -                } -            }, R.string.menu_beam_preferences).show(); - -            return; -        } - -        mNfcAdapter.invokeBeam(this); -    }      private void scanQrCode() {          Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class); @@ -426,14 +380,14 @@ public class ViewKeyActivity extends BaseActivity implements      private void certifyImmediate() {          Intent intent = new Intent(this, CertifyKeyActivity.class); -        intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId}); +        intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] {mMasterKeyId});          startCertifyIntent(intent);      }      private void startCertifyIntent(Intent intent) {          // Message is received after signing is done in KeychainIntentService -        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this) { +        ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -487,15 +441,15 @@ public class ViewKeyActivity extends BaseActivity implements              HashMap<String, Object> data = providerHelper.getGenericData(                      baseUri, -                    new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, -                    new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); +                    new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, +                    new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});              exportHelper.showExportKeysDialog( -                    new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, +                    new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},                      Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)              );          } catch (ProviderHelper.NotFoundException e) { -            Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); +            Notify.create(this, R.string.error_key_not_found, Notify.Style.ERROR).show();              Log.e(Constants.TAG, "Key not found", e);          }      } @@ -515,7 +469,7 @@ public class ViewKeyActivity extends BaseActivity implements          // Create a new Messenger for the communication back          Messenger messenger = new Messenger(returnHandler);          DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, -                new long[]{ mMasterKeyId }); +                new long[] {mMasterKeyId});          deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog");      } @@ -532,25 +486,25 @@ public class ViewKeyActivity extends BaseActivity implements              String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);              if (fp == null) { -                Notify.createNotify(this, "Error scanning fingerprint!", +                Notify.create(this, "Error scanning fingerprint!",                          Notify.LENGTH_LONG, Notify.Style.ERROR).show();                  return;              }              if (mFingerprint.equalsIgnoreCase(fp)) {                  certifyImmediate();              } else { -                Notify.createNotify(this, "Fingerprints did not match!", +                Notify.create(this, "Fingerprints did not match!",                          Notify.LENGTH_LONG, Notify.Style.ERROR).show();              }              return;          } -        if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK){ +        if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {              deleteKey();          } -        if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK){ +        if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {              exportToFile(mDataUri, mExportHelper, mProviderHelper);          } @@ -565,14 +519,14 @@ public class ViewKeyActivity extends BaseActivity implements      private void encrypt(Uri dataUri, boolean text) {          // If there is no encryption key, don't bother.          if (!mHasEncrypt) { -            Notify.showNotify(this, R.string.error_no_encrypt_subkey, Notify.Style.ERROR); +            Notify.create(this, R.string.error_no_encrypt_subkey, Notify.Style.ERROR).show();              return;          }          try {              long keyId = new ProviderHelper(this)                      .getCachedPublicKeyRing(dataUri)                      .extractOrGetMasterKeyId(); -            long[] encryptionKeyIds = new long[]{keyId}; +            long[] encryptionKeyIds = new long[] {keyId};              Intent intent;              if (text) {                  intent = new Intent(this, EncryptTextActivity.class); @@ -608,7 +562,7 @@ public class ViewKeyActivity extends BaseActivity implements          entries.add(keyEntry);          // Message is received after importing is done in KeychainIntentService -        KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler(this) { +        ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); @@ -710,98 +664,9 @@ public class ViewKeyActivity extends BaseActivity implements          loadTask.execute();      } -    /** -     * NFC: Initialize NFC sharing if OS and device supports it -     */ -    @TargetApi(Build.VERSION_CODES.JELLY_BEAN) -    private void initNfc(final Uri dataUri) { -        // check if NFC Beam is supported (>= Android 4.1) -        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - -            // Implementation for the CreateNdefMessageCallback interface -            mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() { -                @Override -                public NdefMessage createNdefMessage(NfcEvent event) { -                    /* -                     * When a device receives a push with an AAR in it, the application specified in the AAR is -                     * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to -                     * guarantee that this activity starts when receiving a beamed message. For now, this code -                     * uses the tag dispatch system. -                     */ -                    return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, -                            mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); -                } -            }; - -            // Implementation for the OnNdefPushCompleteCallback interface -            mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() { -                @Override -                public void onNdefPushComplete(NfcEvent event) { -                    // A handler is needed to send messages to the activity when this -                    // callback occurs, because it happens from a binder thread -                    mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); -                } -            }; - -            // Check for available NFC Adapter -            mNfcAdapter = NfcAdapter.getDefaultAdapter(this); -            if (mNfcAdapter != null) { -                /* -                 * Retrieve mNfcKeyringBytes here asynchronously (to not block the UI) -                 * and init nfc adapter afterwards. -                 * mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process -                 * has no permissions to query the Uri. -                 */ -                AsyncTask<Void, Void, Void> initTask = -                        new AsyncTask<Void, Void, Void>() { -                            protected Void doInBackground(Void... unused) { -                                try { -                                    Uri blobUri = -                                            KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); -                                    mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData( -                                            blobUri, -                                            KeychainContract.KeyRingData.KEY_RING_DATA, -                                            ProviderHelper.FIELD_TYPE_BLOB); -                                } catch (ProviderHelper.NotFoundException e) { -                                    Log.e(Constants.TAG, "key not found!", e); -                                } - -                                // no AsyncTask return (Void) -                                return null; -                            } - -                            protected void onPostExecute(Void unused) { -                                // Register callback to set NDEF message -                                mNfcAdapter.setNdefPushMessageCallback(mNdefCallback, -                                        ViewKeyActivity.this); -                                // Register callback to listen for message-sent success -                                mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback, -                                        ViewKeyActivity.this); -                            } -                        }; - -                initTask.execute(); -            } -        } -    } - -    /** -     * NFC: This handler receives a message from onNdefPushComplete -     */ -    private final Handler mNfcHandler = new Handler() { -        @Override -        public void handleMessage(Message msg) { -            switch (msg.what) { -                case NFC_SENT: -                    Notify.showNotify( -                            ViewKeyActivity.this, R.string.nfc_successful, Notify.Style.INFO); -                    break; -            } -        } -    };      // These are the rows that we will retrieve. -    static final String[] PROJECTION = new String[]{ +    static final String[] PROJECTION = new String[] {              KeychainContract.KeyRings._ID,              KeychainContract.KeyRings.MASTER_KEY_ID,              KeychainContract.KeyRings.USER_ID, @@ -1018,4 +883,4 @@ public class ViewKeyActivity extends BaseActivity implements      public void onLoaderReset(Loader<Cursor> loader) {      } -} +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 95a6faea9..6bd3a9303 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;  import org.sufficientlysecure.keychain.ui.util.Notify;  import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;  import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.NfcHelper;  import java.io.IOException; @@ -68,10 +69,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements      private View mFingerprintClipboardButton;      private View mKeyShareButton;      private View mKeyClipboardButton; +    private View mKeyNfcButton;      private ImageButton mKeySafeSlingerButton;      private View mKeyUploadButton;      ProviderHelper mProviderHelper; +    NfcHelper mNfcHelper;      private static final int LOADER_ID_UNIFIED = 0; @@ -83,6 +86,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements          View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer());          mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); +        mNfcHelper = new NfcHelper(getActivity(), mProviderHelper);          mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint);          mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code); @@ -90,6 +94,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements          mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);          mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);          mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); +        mKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);          mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);          mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);          mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); @@ -128,6 +133,14 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements                  share(mDataUri, mProviderHelper, false, true);              }          }); + +        mKeyNfcButton.setOnClickListener(new View.OnClickListener() { +            @Override +            public void onClick(View v) { +                mNfcHelper.invokeNfcBeam(); +            } +        }); +          mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) { @@ -186,13 +199,13 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements                  } else {                      message = getResources().getString(R.string.key_copied_to_clipboard);                  } -                Notify.showNotify(getActivity(), message, Notify.Style.OK); +                Notify.create(getActivity(), message, Notify.Style.OK).show();              } else {                  // Android will fail with android.os.TransactionTooLargeException if key is too big                  // see http://www.lonestarprod.com/?p=34                  if (content.length() >= 86389) { -                    Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing, -                            Notify.Style.ERROR); +                    Notify.create(getActivity(), R.string.key_too_big_for_sharing, +                            Notify.Style.ERROR).show();                      return;                  } @@ -210,10 +223,10 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements              }          } catch (PgpGeneralException | IOException e) {              Log.e(Constants.TAG, "error processing key!", e); -            Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.error_key_processing, Notify.Style.ERROR).show();          } catch (ProviderHelper.NotFoundException e) {              Log.e(Constants.TAG, "key not found!", e); -            Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); +            Notify.create(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR).show();          }      } @@ -255,9 +268,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements          // Prepare the loaders. Either re-connect with an existing ones,          // or start new ones.          getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + +        // Prepare the NfcHelper +        mNfcHelper.initNfc(mDataUri);      } -    static final String[] UNIFIED_PROJECTION = new String[]{ +    static final String[] UNIFIED_PROJECTION = new String[] {              KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,              KeyRings.USER_ID, KeyRings.FINGERPRINT,              KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED, @@ -362,4 +378,5 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements          startActivityForResult(uploadIntent, 0);      } -} + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index e20796f8f..d5870d8c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -50,12 +50,12 @@ import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;  import org.sufficientlysecure.keychain.util.Log;  import java.util.ArrayList; -import java.util.Date;  import java.util.Hashtable;  import java.util.List; @@ -362,23 +362,26 @@ public class ViewKeyTrustFragment extends LoaderFragment implements          // Create a new Messenger for the communication back after proof work is done          // -        KeychainIntentServiceHandler handler = new KeychainIntentServiceHandler(getActivity(), -                getString(R.string.progress_verifying_signature), ProgressDialog.STYLE_HORIZONTAL) { +        ServiceProgressHandler handler = new ServiceProgressHandler( +                getActivity(), +                getString(R.string.progress_verifying_signature), +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message);                  if (message.arg1 == MessageStatus.OKAY.ordinal()) {                      Bundle returnData = message.getData(); -                    String msg = returnData.getString(KeychainIntentServiceHandler.DATA_MESSAGE); +                    String msg = returnData.getString(ServiceProgressHandler.DATA_MESSAGE);                      SpannableStringBuilder ssb = new SpannableStringBuilder();                      if ((msg != null) && msg.equals("OK")) {                          //yay -                        String proofUrl = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL); -                        String presenceUrl = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL); -                        String presenceLabel = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL); +                        String proofUrl = returnData.getString(ServiceProgressHandler.KEYBASE_PROOF_URL); +                        String presenceUrl = returnData.getString(ServiceProgressHandler.KEYBASE_PRESENCE_URL); +                        String presenceLabel = returnData.getString(ServiceProgressHandler.KEYBASE_PRESENCE_LABEL);                          String proofLabel;                          switch (proof.getType()) { @@ -429,7 +432,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements                          ssb.append(" ").append(getString(R.string.keybase_contained_signature));                      } else {                          // verification failed! -                        msg = returnData.getString(KeychainIntentServiceHandler.DATA_ERROR); +                        msg = returnData.getString(ServiceProgressHandler.DATA_ERROR);                          ssb.append(getString(R.string.keybase_proof_failure));                          if (msg == null) {                              msg = getString(R.string.keybase_unknown_proof_failure); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index f512ecca2..581a96e52 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;  import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler;  import org.sufficientlysecure.keychain.util.Log;  import java.util.HashMap; @@ -135,9 +135,12 @@ public class DeleteKeyDialogFragment extends DialogFragment {                  intent.setAction(KeychainIntentService.ACTION_DELETE);                  // Message is received after importing is done in KeychainIntentService -                KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( -                        getActivity(), getString(R.string.progress_deleting), -                        ProgressDialog.STYLE_HORIZONTAL, true) { +                ServiceProgressHandler saveHandler = new ServiceProgressHandler( +                        getActivity(), +                        getString(R.string.progress_deleting), +                        ProgressDialog.STYLE_HORIZONTAL, +                        true, +                        ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {                      @Override                      public void handleMessage(Message message) {                          super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index 7ac85781f..63b6d26ac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -190,7 +190,7 @@ public class FileDialogFragment extends DialogFragment {                          mFile = file;                          mFilename.setText(mFile.getName());                      } else { -                        Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR); +                        Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR).show();                      }                  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java index df7943f55..b58f584c8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java @@ -32,23 +32,43 @@ import android.view.View;  import android.view.View.OnClickListener;  import android.widget.Button; +import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.CloudImportService;  import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.util.Log;  public class ProgressDialogFragment extends DialogFragment {      private static final String ARG_MESSAGE = "message";      private static final String ARG_STYLE = "style";      private static final String ARG_CANCELABLE = "cancelable"; +    private static final String ARG_SERVICE_TYPE = "service_class"; + +    public static enum ServiceType { +        KEYCHAIN_INTENT, +        CLOUD_IMPORT +    } + +    ServiceType mServiceType;      boolean mCanCancel = false, mPreventCancel = false, mIsCancelled = false; -    /** Creates new instance of this fragment */ -    public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) { +    /** +     * creates a new instance of this fragment +     * @param message the message to be displayed initially above the progress bar +     * @param style the progress bar style, as defined in ProgressDialog (horizontal or spinner) +     * @param cancelable should we let the user cancel this operation +     * @param serviceType which Service this progress dialog is meant for +     * @return +     */ +    public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable, +                                                     ServiceType serviceType) {          ProgressDialogFragment frag = new ProgressDialogFragment();          Bundle args = new Bundle();          args.putString(ARG_MESSAGE, message);          args.putInt(ARG_STYLE, style);          args.putBoolean(ARG_CANCELABLE, cancelable); +        args.putSerializable(ARG_SERVICE_TYPE, serviceType);          frag.setArguments(args); @@ -106,6 +126,7 @@ public class ProgressDialogFragment extends DialogFragment {          String message = getArguments().getString(ARG_MESSAGE);          int style = getArguments().getInt(ARG_STYLE);          mCanCancel = getArguments().getBoolean(ARG_CANCELABLE); +        mServiceType = (ServiceType) getArguments().getSerializable(ARG_SERVICE_TYPE);          dialog.setMessage(message);          dialog.setProgressStyle(style); @@ -175,9 +196,22 @@ public class ProgressDialogFragment extends DialogFragment {                  // send a cancel message. note that this message will be handled by                  // KeychainIntentService.onStartCommand, which runs in this thread,                  // not the service one, and will not queue up a command. -                Intent intent = new Intent(getActivity(), KeychainIntentService.class); -                intent.setAction(KeychainIntentService.ACTION_CANCEL); -                getActivity().startService(intent); +                Intent serviceIntent = null; + +                switch (mServiceType) { +                    case CLOUD_IMPORT: +                        serviceIntent = new Intent(getActivity(), CloudImportService.class); +                        break; +                    case KEYCHAIN_INTENT: +                        serviceIntent = new Intent(getActivity(), KeychainIntentService.class); +                        break; +                    default: +                        //should never happen, unless we forget to include a ServiceType enum case +                        Log.e(Constants.TAG, "Unrecognized ServiceType at ProgressDialogFragment"); +                } + +                serviceIntent.setAction(KeychainIntentService.ACTION_CANCEL); +                getActivity().startService(serviceIntent);              }          }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 9736b5765..7e07ed818 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -18,10 +18,7 @@  package org.sufficientlysecure.keychain.ui.util;  import android.app.Activity; -import android.content.res.Resources;  import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager;  import android.view.View;  import android.view.ViewGroup; @@ -40,135 +37,58 @@ import org.sufficientlysecure.keychain.util.FabContainer;   */  public class Notify { -    public static enum Style {OK, WARN, INFO, ERROR} +    public static enum Style { +        OK, WARN, ERROR; + +        public void applyToBar(Snackbar bar) { + +            switch (this) { +                case OK: +                    // bar.actionColorResource(R.color.android_green_light); +                    bar.lineColorResource(R.color.android_green_light); +                    break; +                case WARN: +                    // bar.textColorResource(R.color.android_orange_light); +                    bar.lineColorResource(R.color.android_orange_light); +                    break; +                case ERROR: +                    // bar.textColorResource(R.color.android_red_light); +                    bar.lineColorResource(R.color.android_red_light); +                    break; +            } + +        } +    }      public static final int LENGTH_INDEFINITE = 0;      public static final int LENGTH_LONG = 3500; -    /** -     * Shows a simple in-layout notification with the CharSequence given as parameter -     * @param text     Text to show -     * @param style    Notification styling -     */ -    public static void showNotify(final Activity activity, CharSequence text, Style style) { - -        Snackbar bar = getSnackbar(activity) +    public static Showable create(final Activity activity, String text, int duration, Style style, +                                  final ActionListener actionListener, int actionResId) { +        final Snackbar snackbar = Snackbar.with(activity) +                .type(SnackbarType.MULTI_LINE)                  .text(text); -        switch (style) { -            case OK: -                break; -            case WARN: -                bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); -                break; -            case ERROR: -                bar.textColor(activity.getResources().getColor(R.color.android_red_light)); -                break; -        } - -        showSnackbar(activity, bar); - -    } - -    public static Showable createNotify (final Activity activity, int resId, int duration, Style style) { -        final Snackbar bar = getSnackbar(activity) -                .text(resId); -          if (duration == LENGTH_INDEFINITE) { -            bar.duration(SnackbarDuration.LENGTH_INDEFINITE); +            snackbar.duration(SnackbarDuration.LENGTH_INDEFINITE);          } else { -            bar.duration(duration); +            snackbar.duration(duration);          } -        switch (style) { -            case OK: -                bar.actionColor(activity.getResources().getColor(R.color.android_green_light)); -                break; -            case WARN: -                bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); -                break; -            case ERROR: -                bar.textColor(activity.getResources().getColor(R.color.android_red_light)); -                break; -        } +        style.applyToBar(snackbar); -        return new Showable () { -            @Override -            public void show() { -                showSnackbar(activity, bar); -            } -        }; -    } - -    public static Showable createNotify(Activity activity, int resId, int duration, Style style, -                                        final ActionListener listener, int resIdAction) { -        return createNotify(activity, activity.getString(resId), duration, style, listener, resIdAction); -    } - -    public static Showable createNotify(Activity activity, String msg, int duration, Style style) { -        return createNotify(activity, msg, duration, style, null, 0); -    } - -    public static Showable createNotify(final Activity activity, String msg, int duration, Style style, -                                        final ActionListener listener, int resIdAction) { - -        final Snackbar bar = getSnackbar(activity) -                .text(msg); - -        if (listener != null) { -            bar.actionLabel(resIdAction); -            bar.actionListener(new ActionClickListener() { -                @Override -                public void onActionClicked(Snackbar snackbar) { -                    listener.onAction(); -                } -            }); -        } - -        if (duration == LENGTH_INDEFINITE) { -            bar.duration(SnackbarDuration.LENGTH_INDEFINITE); -        } else { -            bar.duration(duration); -        } - -        switch (style) { -            case OK: -                bar.actionColor(activity.getResources().getColor(R.color.android_green_light)); -                break; -            case WARN: -                bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); -                break; -            case ERROR: -                bar.textColor(activity.getResources().getColor(R.color.android_red_light)); -                break; +        if (actionListener != null) { +            snackbar.actionLabel(actionResId) +                    .actionListener(new ActionClickListener() { +                        @Override +                        public void onActionClicked(Snackbar snackbar) { +                            actionListener.onAction(); +                        } +                    });          } -        return new Showable () { -            @Override -            public void show() { -                showSnackbar(activity, bar); -            } -        }; - -    } - -    /** -     * Shows a simple in-layout notification with the resource text from given id -     * @param resId    ResourceId of notification text -     * @param style    Notification styling -     * @throws Resources.NotFoundException -     */ -    public static void showNotify(Activity activity, int resId, Style style) throws Resources.NotFoundException { -        showNotify(activity, activity.getResources().getText(resId), style); -    } - -    private static Snackbar getSnackbar(final Activity activity) { -        Snackbar bar = Snackbar.with(activity) -                .type(SnackbarType.MULTI_LINE) -                .duration(SnackbarDuration.LENGTH_LONG); -          if (activity instanceof FabContainer) { -            bar.eventListener(new EventListenerAdapter() { +            snackbar.eventListener(new EventListenerAdapter() {                  @Override                  public void onShow(Snackbar snackbar) {                      ((FabContainer) activity).fabMoveUp(snackbar.getHeight()); @@ -180,37 +100,84 @@ public class Notify {                  }              });          } -        return bar; -    } -    private static void showSnackbar(Activity activity, Snackbar snackbar) { -        if (activity instanceof FragmentActivity) { -            FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager(); +        return new Showable() { +            @Override +            public void show() { +                SnackbarManager.show(snackbar, activity); +            } -            int count = fragmentManager.getBackStackEntryCount(); -            Fragment fragment = fragmentManager.getFragments().get(count > 0 ? count - 1 : 0); +            @Override +            public void show(Fragment fragment) { +                if (fragment != null) { +                    View view = fragment.getView(); + +                    if (view != null && view instanceof ViewGroup) { +                        SnackbarManager.show(snackbar, (ViewGroup) view); +                        return; +                    } +                } -            if (fragment != null) { -                View view = fragment.getView(); +                show(); +            } -                if (view != null) { -                    SnackbarManager.show(snackbar, (ViewGroup) view); +            @Override +            public void show(ViewGroup viewGroup) { +                if (viewGroup != null) { +                    SnackbarManager.show(snackbar, viewGroup);                      return;                  } + +                show();              } -        } +        }; +    } + +    public static Showable create(Activity activity, String text, int duration, Style style) { +        return create(activity, text, duration, style, null, -1); +    } + +    public static Showable create(Activity activity, String text, Style style) { +        return create(activity, text, LENGTH_LONG, style); +    } -        SnackbarManager.show(snackbar); +    public static Showable create(Activity activity, int textResId, int duration, Style style, +                                  ActionListener actionListener, int actionResId) { +        return create(activity, activity.getString(textResId), duration, style, actionListener, actionResId); +    } + +    public static Showable create(Activity activity, int textResId, int duration, Style style) { +        return create(activity, activity.getString(textResId), duration, style); +    } + +    public static Showable create(Activity activity, int textResId, Style style) { +        return create(activity, activity.getString(textResId), style);      }      public interface Showable { + +        /** +         * Shows the notification on the bottom of the Activity. +         */          public void show(); +        /** +         * Shows the notification on the bottom of the Fragment. +         */ +        public void show(Fragment fragment); + +        /** +         * Shows the notification on the given ViewGroup. +         * The viewGroup should be either a RelativeLayout or FrameLayout. +         */ +        public void show(ViewGroup viewGroup); +      }      public interface ActionListener { +          public void onAction();      } -}
\ No newline at end of file +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java index 7b164f2b2..7efb7c5af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java @@ -19,9 +19,7 @@ package org.sufficientlysecure.keychain.util;  import android.app.ProgressDialog;  import android.content.Intent; -import android.net.Uri;  import android.os.Bundle; -import android.os.Handler;  import android.os.Message;  import android.os.Messenger;  import android.support.v4.app.FragmentActivity; @@ -29,11 +27,9 @@ import android.support.v4.app.FragmentActivity;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;  import java.io.File; @@ -102,9 +98,10 @@ public class ExportHelper {          intent.putExtra(KeychainIntentService.EXTRA_DATA, data);          // Message is received after exporting is done in KeychainIntentService -        KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity, +        ServiceProgressHandler exportHandler = new ServiceProgressHandler(mActivity,                  mActivity.getString(R.string.progress_exporting), -                ProgressDialog.STYLE_HORIZONTAL) { +                ProgressDialog.STYLE_HORIZONTAL, +                ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) {              public void handleMessage(Message message) {                  // handle messages by standard KeychainIntentServiceHandler first                  super.handleMessage(message); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java new file mode 100644 index 000000000..e4e4e4d05 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2015 Kent Nguyen <kentnguyen@moneylover.me> + * + * 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.util; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcEvent; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.Notify; + +import java.lang.ref.WeakReference; + +/** + * This class contains NFC functionality that can be shared across Fragments or Activities. + */ + +public class NfcHelper { + +    private Activity mActivity; +    private ProviderHelper mProviderHelper; + +    /** +     * NFC: This handler receives a message from onNdefPushComplete +     */ +    private static NfcHandler mNfcHandler; + +    private NfcAdapter mNfcAdapter; +    private NfcAdapter.CreateNdefMessageCallback mNdefCallback; +    private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback; +    private byte[] mNfcKeyringBytes; +    private static final int NFC_SENT = 1; + +    /** +     * Initializes the NfcHelper. +     */ +    public NfcHelper(final Activity activity, final ProviderHelper providerHelper) { +        mActivity = activity; +        mProviderHelper = providerHelper; + +        mNfcHandler = new NfcHandler(mActivity); +    } + +    /** +     * Return true if the NFC Adapter of this Helper has any features enabled. +     * +     * @return true if this NFC Adapter has any features enabled +     */ +    public boolean isEnabled() { +        return mNfcAdapter.isEnabled(); +    } + +    /** +     * NFC: Initialize NFC sharing if OS and device supports it +     */ +    @TargetApi(Build.VERSION_CODES.JELLY_BEAN) +    public void initNfc(final Uri dataUri) { +        // check if NFC Beam is supported (>= Android 4.1) +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + +            // Implementation for the CreateNdefMessageCallback interface +            mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() { +                @Override +                public NdefMessage createNdefMessage(NfcEvent event) { +                    /* +                     * When a device receives a push with an AAR in it, the application specified in the AAR is +                     * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to +                     * guarantee that this activity starts when receiving a beamed message. For now, this code +                     * uses the tag dispatch system. +                     */ +                    return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, +                            mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); +                } +            }; + +            // Implementation for the OnNdefPushCompleteCallback interface +            mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() { +                @Override +                public void onNdefPushComplete(NfcEvent event) { +                    // A handler is needed to send messages to the activity when this +                    // callback occurs, because it happens from a binder thread +                    mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); +                } +            }; + +            // Check for available NFC Adapter +            mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity); +            if (mNfcAdapter != null) { +                /* +                 * Retrieve mNfcKeyringBytes here asynchronously (to not block the UI) +                 * and init nfc adapter afterwards. +                 * mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process +                 * has no permissions to query the Uri. +                 */ +                AsyncTask<Void, Void, Void> initTask = +                        new AsyncTask<Void, Void, Void>() { +                            protected Void doInBackground(Void... unused) { +                                try { +                                    Uri blobUri = +                                            KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); +                                    mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData( +                                            blobUri, +                                            KeychainContract.KeyRingData.KEY_RING_DATA, +                                            ProviderHelper.FIELD_TYPE_BLOB); +                                } catch (ProviderHelper.NotFoundException e) { +                                    Log.e(Constants.TAG, "key not found!", e); +                                } + +                                // no AsyncTask return (Void) +                                return null; +                            } + +                            protected void onPostExecute(Void unused) { +                                // Register callback to set NDEF message +                                mNfcAdapter.setNdefPushMessageCallback(mNdefCallback, +                                        mActivity); +                                // Register callback to listen for message-sent success +                                mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback, +                                        mActivity); +                            } +                        }; + +                initTask.execute(); +            } +        } +    } + +    @TargetApi(Build.VERSION_CODES.LOLLIPOP) +    public void invokeNfcBeam() { +        // Check if device supports NFC +        if (!mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { +            Notify.create(mActivity, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show(); +            return; +        } +        // Check for available NFC Adapter +        mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity); +        if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { +            Notify.create(mActivity, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { +                @Override +                public void onAction() { +                    Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS); +                    mActivity.startActivity(intentSettings); +                } +            }, R.string.menu_nfc_preferences).show(); + +            return; +        } + +        if (!mNfcAdapter.isNdefPushEnabled()) { +            Notify.create(mActivity, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { +                @Override +                public void onAction() { +                    Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); +                    mActivity.startActivity(intentSettings); +                } +            }, R.string.menu_beam_preferences).show(); + +            return; +        } + +        mNfcAdapter.invokeBeam(mActivity); +    } + +    /** +     * A static subclass of {@link Handler} with a {@link WeakReference} to an {@link Activity} to avoid memory leaks. +     */ +    private static class NfcHandler extends Handler { +        private final WeakReference<Activity> mActivityReference; + +        public NfcHandler(Activity activity) { +            mActivityReference = new WeakReference<>(activity); +        } + +        @Override +        public void handleMessage(Message msg) { +            Activity activity = mActivityReference.get(); + +            if (activity != null) { +                switch (msg.what) { +                    case NFC_SENT: +                        Notify.create(activity, R.string.nfc_successful, Notify.Style.OK).show(); +                        break; +                } +            } +        } +    } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java index 6f9cb277e..5a314ad0b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java @@ -83,10 +83,22 @@ public class ParcelableFileCache<E extends Parcelable> {      } +    /** +     * Reads from cache file and deletes it afterward. Convenience function for readCache(boolean). +     * @return an IteratorWithSize object containing entries read from the cache file +     * @throws IOException +     */      public IteratorWithSize<E> readCache() throws IOException {          return readCache(true);      } +    /** +     * Reads entries from a cache file and returns an IteratorWithSize object containing the entries +     * @param deleteAfterRead if true, the cache file will be deleted after being read +     * @return an IteratorWithSize object containing entries read from the cache file +     * @throws IOException if cache directory/parcel import file does not exist, or a read error +     * occurs +     */      public IteratorWithSize<E> readCache(final boolean deleteAfterRead) throws IOException {          File cacheDir = mContext.getCacheDir(); | 
