diff options
Diffstat (limited to 'OpenKeychain')
183 files changed, 2096 insertions, 1312 deletions
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 2f98a9485..3bcfdda5e 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -26,6 +26,7 @@ dependencies { compile 'com.journeyapps:zxing-android-integration:2.0.1@aar' compile 'com.google.zxing:core:3.0.1' compile 'com.jpardogo.materialtabstrip:library:1.0.8' + compile 'it.neokree:MaterialNavigationDrawer:1.3' compile 'com.nispok:snackbar:2.7.4' } @@ -38,6 +39,11 @@ android { targetSdkVersion 21 } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + /* * To sign release build, create file gradle.properties in ~/.gradle/ with this content: * diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 536b66319..865e0272d 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -75,7 +75,7 @@ android:theme="@style/KeychainTheme" android:label="@string/app_name"> <activity - android:name=".ui.KeyListActivity" + android:name=".ui.MainActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/app_name" android:launchMode="singleTop"> @@ -86,6 +86,11 @@ </intent-filter> </activity> <activity + android:name=".ui.KeyListActivity" + android:configChanges="orientation|screenSize|keyboardHidden|keyboard" + android:label="@string/app_name" + android:windowSoftInputMode="stateAlwaysHidden" /> + <activity android:name=".ui.FirstTimeActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/app_name" diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java index 255ca1cde..3b281876f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -32,10 +32,10 @@ public class CloudSearch { public static ArrayList<ImportKeysListEntry> search(final String query, Preferences.CloudSearchPrefs cloudPrefs) throws Keyserver.CloudSearchFailureException { - final ArrayList<Keyserver> servers = new ArrayList<Keyserver>(); + final ArrayList<Keyserver> servers = new ArrayList<>(); // it's a Vector for sync, multiple threads might report problems - final Vector<Keyserver.CloudSearchFailureException> problems = new Vector<Keyserver.CloudSearchFailureException>(); + final Vector<Keyserver.CloudSearchFailureException> problems = new Vector<>(); if (cloudPrefs.searchKeyserver) { servers.add(new HkpKeyserver(cloudPrefs.keyserver)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 7f07b8162..f39c552a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -234,7 +234,7 @@ public class HkpKeyserver extends Keyserver { @Override public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException, QueryNeedsRepairException { - ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>(); + ArrayList<ImportKeysListEntry> results = new ArrayList<>(); if (query.length() < 3) { throw new QueryTooShortException(); @@ -305,7 +305,7 @@ public class HkpKeyserver extends Keyserver { entry.setRevoked(matcher.group(6).contains("r")); entry.setExpired(matcher.group(6).contains("e")); - ArrayList<String> userIds = new ArrayList<String>(); + ArrayList<String> userIds = new ArrayList<>(); final String uidLines = matcher.group(7); final Matcher uidMatcher = UID_LINE.matcher(uidLines); while (uidMatcher.find()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index d60d7757b..1d5ee76a4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -89,7 +89,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public ImportKeysListEntry createFromParcel(final Parcel source) { ImportKeysListEntry vr = new ImportKeysListEntry(); vr.mPrimaryUserId = source.readString(); - vr.mUserIds = new ArrayList<String>(); + vr.mUserIds = new ArrayList<>(); source.readStringList(vr.mUserIds); vr.mMergedUserIds = (HashMap<String, HashSet<String>>) source.readSerializable(); vr.mKeyId = source.readLong(); @@ -103,7 +103,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.mSecretKey = source.readByte() == 1; vr.mSelected = source.readByte() == 1; vr.mExtraData = source.readString(); - vr.mOrigins = new ArrayList<String>(); + vr.mOrigins = new ArrayList<>(); source.readStringList(vr.mOrigins); return vr; @@ -265,8 +265,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mSecretKey = false; // do not select by default mSelected = false; - mUserIds = new ArrayList<String>(); - mOrigins = new ArrayList<String>(); + mUserIds = new ArrayList<>(); + mOrigins = new ArrayList<>(); } /** @@ -304,7 +304,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { } public void updateMergedUserIds() { - mMergedUserIds = new HashMap<String, HashSet<String>>(); + mMergedUserIds = new HashMap<>(); for (String userId : mUserIds) { String[] userIdSplit = KeyRing.splitUserId(userId); @@ -315,7 +315,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { // email if (userIdSplit[1] != null) { if (!mMergedUserIds.containsKey(userIdSplit[0])) { - HashSet<String> emails = new HashSet<String>(); + HashSet<String> emails = new HashSet<>(); emails.add(userIdSplit[1]); mMergedUserIds.put(userIdSplit[0], emails); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java index 2363a40b3..e310e9a3f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java @@ -36,7 +36,7 @@ public class KeybaseKeyserver extends Keyserver { @Override public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException, QueryNeedsRepairException { - ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>(); + ArrayList<ImportKeysListEntry> results = new ArrayList<>(); if (query.startsWith("0x")) { // cut off "0x" if a user is searching for a key id @@ -81,7 +81,7 @@ public class KeybaseKeyserver extends Keyserver { final int algorithmId = match.getAlgorithmId(); entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitStrength, null)); - ArrayList<String> userIds = new ArrayList<String>(); + ArrayList<String> userIds = new ArrayList<>(); String name = "<keybase.io/" + username + ">"; if (fullName != null) { name = fullName + " " + name; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java index c400eb813..e796bdc91 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -77,6 +77,12 @@ public abstract class BaseOperation implements PassphraseCacheInterface { return mCancelled != null && mCancelled.get(); } + protected void setPreventCancel () { + if (mProgressable != null) { + mProgressable.setPreventCancel(); + } + } + @Override public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException { try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index a5eb95b07..3b391814e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -78,7 +78,7 @@ public class CertifyOperation extends BaseOperation { return new CertifyResult(CertifyResult.RESULT_ERROR, log); } - ArrayList<UncachedKeyRing> certifiedKeys = new ArrayList<UncachedKeyRing>(); + ArrayList<UncachedKeyRing> certifiedKeys = new ArrayList<>(); log.add(LogType.MSG_CRT_CERTIFYING, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 4d466593b..106c62688 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -11,7 +11,6 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; -import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; @@ -29,7 +28,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * create key operations in PgpKeyOperation. It takes care of fetching * and saving the key before and after the operation. * - * @see CertifyActionsParcel + * @see SaveKeyringParcel * */ public class EditKeyOperation extends BaseOperation { 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 6ca28142f..3f3e0a432 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java @@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; @@ -44,9 +45,12 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedOutputStream; @@ -58,6 +62,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** An operation class which implements high level import and export @@ -123,6 +128,35 @@ public class ImportExportOperation extends BaseOperation { } } + public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries, String keyServerUri) { + + Iterator<ParcelableKeyRing> it = entries.iterator(); + int numEntries = entries.size(); + + return importKeyRings(it, numEntries, keyServerUri); + + } + + public ImportKeyResult importKeyRings(ParcelableFileCache<ParcelableKeyRing> cache, String keyServerUri) { + + // get entries from cached file + try { + IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); + int numEntries = it.getSize(); + + return importKeyRings(it, numEntries, keyServerUri); + } catch (IOException e) { + + // Special treatment here, we need a lot + OperationLog log = new OperationLog(); + log.add(LogType.MSG_IMPORT, 0, 0); + log.add(LogType.MSG_IMPORT_ERROR_IO, 0, 0); + + return new ImportKeyResult(ImportKeyResult.RESULT_ERROR, log); + } + + } + public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num, String keyServerUri) { updateProgress(R.string.progress_importing, 0, 100); @@ -131,13 +165,11 @@ public class ImportExportOperation extends BaseOperation { // If there aren't even any keys, do nothing here. if (entries == null || !entries.hasNext()) { - return new ImportKeyResult( - ImportKeyResult.RESULT_FAIL_NOTHING, log, 0, 0, 0, 0, - new long[]{}); + return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, log); } int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0; - ArrayList<Long> importedMasterKeyIds = new ArrayList<Long>(); + ArrayList<Long> importedMasterKeyIds = new ArrayList<>(); boolean cancelled = false; int position = 0; @@ -293,6 +325,16 @@ public class ImportExportOperation extends BaseOperation { position++; } + // Special: consolidate on secret key import (cannot be cancelled!) + if (secret > 0) { + setPreventCancel(); + ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(mProgressable); + log.add(result, 1); + } + + // Special: make sure new data is synced into contacts + ContactSyncAdapterService.requestSync(); + // convert to long array long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()]; for (int i = 0; i < importedMasterKeyIds.size(); ++i) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java new file mode 100644 index 000000000..f10d11684 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java @@ -0,0 +1,103 @@ +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** An operation which promotes a public key ring to a secret one. + * + * This operation can only be applied to public key rings where no secret key + * is available. Doing this "promotes" the public key ring to a secret one + * without secret key material, using a GNU_DUMMY s2k type. + * + */ +public class PromoteKeyOperation extends BaseOperation { + + public PromoteKeyOperation(Context context, ProviderHelper providerHelper, + Progressable progressable, AtomicBoolean cancelled) { + super(context, providerHelper, progressable, cancelled); + } + + public PromoteKeyResult execute(long masterKeyId) { + + OperationLog log = new OperationLog(); + log.add(LogType.MSG_PR, 0); + + // Perform actual type change + UncachedKeyRing promotedRing; + { + + try { + + // This operation is only allowed for pure public keys + // TODO delete secret keys if they are stripped, or have been moved to the card? + if (mProviderHelper.getCachedPublicKeyRing(masterKeyId).hasAnySecret()) { + log.add(LogType.MSG_PR_ERROR_ALREADY_SECRET, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + log.add(LogType.MSG_PR_FETCHING, 1, + KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + CanonicalizedPublicKeyRing pubRing = + mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId); + + // create divert-to-card secret key from public key + promotedRing = pubRing.createDummySecretRing(); + + } catch (PgpKeyNotFoundException e) { + log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } catch (NotFoundException e) { + log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + } + + // If the edit operation didn't succeed, exit here + if (promotedRing == null) { + // error is already logged by modification + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + // Check if the action was cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new PromoteKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null); + } + + // Cannot cancel from here on out! + setPreventCancel(); + + // Save the new keyring. + SaveKeyringResult saveResult = mProviderHelper + .saveSecretKeyRing(promotedRing, new ProgressScaler(mProgressable, 60, 95, 100)); + log.add(saveResult, 1); + + // If the save operation didn't succeed, exit here + if (!saveResult.success()) { + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_PR_SUCCESS, 0); + return new PromoteKeyResult(PromoteKeyResult.RESULT_OK, log, promotedRing.getMasterKeyId()); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index d81577102..86b37fea6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -41,6 +41,9 @@ public class DecryptVerifyResult extends OperationResult { OpenPgpSignatureResult mSignatureResult; OpenPgpMetadata mDecryptMetadata; + // This holds the charset which was specified in the ascii armor, if specified + // https://tools.ietf.org/html/rfc4880#page56 + String mCharset; public long getKeyIdPassphraseNeeded() { return mKeyIdPassphraseNeeded; @@ -84,6 +87,14 @@ public class DecryptVerifyResult extends OperationResult { mDecryptMetadata = decryptMetadata; } + public String getCharset () { + return mCharset; + } + + public void setCharset(String charset) { + mCharset = charset; + } + public boolean isPending() { return (mResult & RESULT_PENDING) == RESULT_PENDING; } 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 ecde90ea6..2d533ed16 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 @@ -79,6 +79,10 @@ public class ImportKeyResult extends OperationResult { mImportedMasterKeyIds = source.createLongArray(); } + public ImportKeyResult(int result, OperationLog log) { + this(result, log, 0, 0, 0, 0, new long[] { }); + } + public ImportKeyResult(int result, OperationLog log, int newKeys, int updatedKeys, int badKeys, int secret, long[] importedMasterKeyIds) { 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 6552948fa..055028064 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 @@ -464,6 +464,7 @@ public abstract class OperationResult implements Parcelable { // secret key modify MSG_MF (LogLevel.START, R.string.msg_mr), + MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial), MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode), MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint), MSG_MF_ERROR_KEYID (LogLevel.ERROR, R.string.msg_mf_error_keyid), @@ -476,6 +477,7 @@ public abstract class OperationResult implements Parcelable { MSG_MF_ERROR_PASSPHRASE_MASTER(LogLevel.ERROR, R.string.msg_mf_error_passphrase_master), MSG_MF_ERROR_PAST_EXPIRY(LogLevel.ERROR, R.string.msg_mf_error_past_expiry), MSG_MF_ERROR_PGP (LogLevel.ERROR, R.string.msg_mf_error_pgp), + MSG_MF_ERROR_RESTRICTED(LogLevel.ERROR, R.string.msg_mf_error_restricted), MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary), MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig), MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing), @@ -537,6 +539,13 @@ public abstract class OperationResult implements Parcelable { MSG_ED_FETCHING (LogLevel.DEBUG, R.string.msg_ed_fetching), MSG_ED_SUCCESS (LogLevel.OK, R.string.msg_ed_success), + // promote key + MSG_PR (LogLevel.START, R.string.msg_pr), + MSG_PR_ERROR_ALREADY_SECRET (LogLevel.ERROR, R.string.msg_pr_error_already_secret), + MSG_PR_ERROR_KEY_NOT_FOUND (LogLevel.ERROR, R.string.msg_pr_error_key_not_found), + MSG_PR_FETCHING (LogLevel.DEBUG, R.string.msg_pr_fetching), + MSG_PR_SUCCESS (LogLevel.OK, R.string.msg_pr_success), + // messages used in UI code MSG_EK_ERROR_DIVERT (LogLevel.ERROR, R.string.msg_ek_error_divert), MSG_EK_ERROR_DUMMY (LogLevel.ERROR, R.string.msg_ek_error_dummy), @@ -546,6 +555,7 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ASKIP_NO_KEY (LogLevel.DEBUG, R.string.msg_dc_askip_no_key), MSG_DC_ASKIP_NOT_ALLOWED (LogLevel.DEBUG, R.string.msg_dc_askip_not_allowed), MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym), + MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset), MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data), MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress), MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file), @@ -636,6 +646,7 @@ public abstract class OperationResult implements Parcelable { MSG_IMPORT_FINGERPRINT_ERROR (LogLevel.ERROR, R.string.msg_import_fingerprint_error), MSG_IMPORT_FINGERPRINT_OK (LogLevel.DEBUG, R.string.msg_import_fingerprint_ok), MSG_IMPORT_ERROR (LogLevel.ERROR, R.string.msg_import_error), + MSG_IMPORT_ERROR_IO (LogLevel.ERROR, R.string.msg_import_error_io), MSG_IMPORT_PARTIAL (LogLevel.ERROR, R.string.msg_import_partial), MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success), @@ -717,7 +728,7 @@ public abstract class OperationResult implements Parcelable { public static class OperationLog implements Iterable<LogEntryParcel> { - private final List<LogEntryParcel> mParcels = new ArrayList<LogEntryParcel>(); + private final List<LogEntryParcel> mParcels = new ArrayList<>(); /// Simple convenience method public void add(LogType type, int indent, Object... parameters) { @@ -742,7 +753,7 @@ public abstract class OperationResult implements Parcelable { } public boolean containsType(LogType type) { - for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) { + for(LogEntryParcel entry : new IterableIterator<>(mParcels.iterator())) { if (entry.mType == type) { return true; } @@ -751,7 +762,7 @@ public abstract class OperationResult implements Parcelable { } public boolean containsWarnings() { - for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) { + for(LogEntryParcel entry : new IterableIterator<>(mParcels.iterator())) { if (entry.mType.mLevel == LogLevel.WARN || entry.mType.mLevel == LogLevel.ERROR) { return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java new file mode 100644 index 000000000..af9aff84a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.operations.results; + +import android.os.Parcel; + +public class PromoteKeyResult extends OperationResult { + + public final Long mMasterKeyId; + + public PromoteKeyResult(int result, OperationLog log, Long masterKeyId) { + super(result, log); + mMasterKeyId = masterKeyId; + } + + public PromoteKeyResult(Parcel source) { + super(source); + mMasterKeyId = source.readLong(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(mMasterKeyId); + } + + public static Creator<PromoteKeyResult> CREATOR = new Creator<PromoteKeyResult>() { + public PromoteKeyResult createFromParcel(final Parcel source) { + return new PromoteKeyResult(source); + } + + public PromoteKeyResult[] newArray(final int size) { + return new PromoteKeyResult[size]; + } + }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index 57daf3430..c336f8502 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -37,6 +37,7 @@ public class SignEncryptResult extends OperationResult { int mNfcAlgo; Date mNfcTimestamp; String mNfcPassphrase; + byte[] mDetachedSignature; public long getKeyIdPassphraseNeeded() { return mKeyIdPassphraseNeeded; @@ -54,6 +55,10 @@ public class SignEncryptResult extends OperationResult { mNfcPassphrase = passphrase; } + public void setDetachedSignature(byte[] detachedSignature) { + mDetachedSignature = detachedSignature; + } + public long getNfcKeyId() { return mNfcKeyId; } @@ -74,6 +79,10 @@ public class SignEncryptResult extends OperationResult { return mNfcPassphrase; } + public byte[] getDetachedSignature() { + return mDetachedSignature; + } + public boolean isPending() { return (mResult & RESULT_PENDING) == RESULT_PENDING; } @@ -87,6 +96,7 @@ public class SignEncryptResult extends OperationResult { mNfcHash = source.readInt() != 0 ? source.createByteArray() : null; mNfcAlgo = source.readInt(); mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null; + mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; } public int describeContents() { @@ -108,6 +118,12 @@ public class SignEncryptResult extends OperationResult { } else { dest.writeInt(0); } + if (mDetachedSignature != null) { + dest.writeInt(1); + dest.writeByteArray(mDetachedSignature); + } else { + dest.writeInt(0); + } } public static final Creator<SignEncryptResult> CREATOR = new Creator<SignEncryptResult>() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index db0a9b137..bbf136dac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.openpgp.PGPKeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.IterableIterator; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java index 3539a4ceb..b026d9257 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -53,7 +53,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canSign() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.SIGN_DATA) != 0; } @@ -66,7 +66,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canCertify() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0; } @@ -79,7 +79,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canEncrypt() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0; } @@ -93,7 +93,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canAuthenticate() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java index 85ef3eaa4..c2506685d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java @@ -18,9 +18,11 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.S2K; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -76,7 +78,7 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing { public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() { @SuppressWarnings("unchecked") final Iterator<PGPPublicKey> it = getRing().getPublicKeys(); - return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() { + return new IterableIterator<>(new Iterator<CanonicalizedPublicKey>() { @Override public boolean hasNext() { return it.hasNext(); @@ -94,4 +96,13 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing { }); } + /** Create a dummy secret ring from this key */ + public UncachedKeyRing createDummySecretRing () { + + PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), + S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); + return new UncachedKeyRing(secRing); + + } + }
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 6ccadac2e..40f2f48ad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -182,7 +182,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { * @return */ public LinkedList<Integer> getSupportedHashAlgorithms() { - LinkedList<Integer> supported = new LinkedList<Integer>(); + LinkedList<Integer> supported = new LinkedList<>(); if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { // No support for MD5 @@ -247,7 +247,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { int signatureType; if (cleartext) { - // for sign-only ascii text + // for sign-only ascii text (cleartext signature) signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; } else { signatureType = PGPSignature.BINARY_DOCUMENT; @@ -262,11 +262,9 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { spGen.setSignatureCreationTime(false, nfcCreationTimestamp); signatureGenerator.setHashedSubpackets(spGen.generate()); return signatureGenerator; - } catch (PgpKeyNotFoundException e) { + } catch (PgpKeyNotFoundException | PGPException e) { // TODO: simply throw PGPException! throw new PgpGeneralException("Error initializing signature!", e); - } catch (PGPException e) { - throw new PgpGeneralException("Error initializing signature!", e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java index eb589c3f9..b5f6a5b09 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java @@ -18,27 +18,19 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.bcpg.S2K; -import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { @@ -94,7 +86,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { public IterableIterator<CanonicalizedSecretKey> secretKeyIterator() { final Iterator<PGPSecretKey> it = mRing.getSecretKeys(); - return new IterableIterator<CanonicalizedSecretKey>(new Iterator<CanonicalizedSecretKey>() { + return new IterableIterator<>(new Iterator<CanonicalizedSecretKey>() { @Override public boolean hasNext() { return it.hasNext(); @@ -114,7 +106,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() { final Iterator<PGPPublicKey> it = getRing().getPublicKeys(); - return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() { + return new IterableIterator<>(new Iterator<CanonicalizedPublicKey>() { @Override public boolean hasNext() { return it.hasNext(); @@ -133,7 +125,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { } public HashMap<String,String> getLocalNotationData() { - HashMap<String,String> result = new HashMap<String,String>(); + HashMap<String,String> result = new HashMap<>(); Iterator<PGPSignature> it = getRing().getPublicKey().getKeySignatures(); while (it.hasNext()) { WrappedSignature sig = new WrappedSignature(it.next()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index aa324c7ed..ed4715681 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.pgp; import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.Log; @@ -33,7 +32,7 @@ public class OpenPgpSignatureResultBuilder { // OpenPgpSignatureResult private boolean mSignatureOnly = false; private String mPrimaryUserId; - private ArrayList<String> mUserIds = new ArrayList<String>(); + private ArrayList<String> mUserIds = new ArrayList<>(); private long mKeyId; // builder diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index b58df085f..a69c5fe36 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -28,7 +28,6 @@ import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedDataList; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPOnePassSignatureList; import org.spongycastle.openpgp.PGPPBEEncryptedData; @@ -36,6 +35,7 @@ import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; @@ -83,6 +83,7 @@ public class PgpDecryptVerify extends BaseOperation { private Set<Long> mAllowedKeyIds; private boolean mDecryptMetadataOnly; private byte[] mDecryptedSessionKey; + private byte[] mDetachedSignature; protected PgpDecryptVerify(Builder builder) { super(builder.mContext, builder.mProviderHelper, builder.mProgressable); @@ -96,6 +97,7 @@ public class PgpDecryptVerify extends BaseOperation { this.mAllowedKeyIds = builder.mAllowedKeyIds; this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly; this.mDecryptedSessionKey = builder.mDecryptedSessionKey; + this.mDetachedSignature = builder.mDetachedSignature; } public static class Builder { @@ -103,15 +105,16 @@ public class PgpDecryptVerify extends BaseOperation { private Context mContext; private ProviderHelper mProviderHelper; private InputData mData; - private OutputStream mOutStream; // optional + private OutputStream mOutStream = null; private Progressable mProgressable = null; private boolean mAllowSymmetricDecryption = true; private String mPassphrase = null; private Set<Long> mAllowedKeyIds = null; private boolean mDecryptMetadataOnly = false; private byte[] mDecryptedSessionKey = null; + private byte[] mDetachedSignature = null; public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, @@ -156,6 +159,17 @@ public class PgpDecryptVerify extends BaseOperation { return this; } + /** + * If detachedSignature != null, it will be used exclusively to verify the signature + * + * @param detachedSignature + * @return + */ + public Builder setDetachedSignature(byte[] detachedSignature) { + mDetachedSignature = detachedSignature; + return this; + } + public PgpDecryptVerify build() { return new PgpDecryptVerify(this); } @@ -166,22 +180,30 @@ public class PgpDecryptVerify extends BaseOperation { */ public DecryptVerifyResult execute() { try { - // automatically works with ascii armor input and binary - InputStream in = PGPUtil.getDecoderStream(mData.getInputStream()); + if (mDetachedSignature != null) { + Log.d(Constants.TAG, "Detached signature present, verifying with this signature only"); - if (in instanceof ArmoredInputStream) { - ArmoredInputStream aIn = (ArmoredInputStream) in; - // it is ascii armored - Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); - - if (aIn.isClearText()) { - // a cleartext signature, verify it with the other method - return verifyCleartextSignature(aIn, 0); + return verifyDetachedSignature(mData.getInputStream(), 0); + } else { + // automatically works with PGP ascii armor and PGP binary + InputStream in = PGPUtil.getDecoderStream(mData.getInputStream()); + + if (in instanceof ArmoredInputStream) { + ArmoredInputStream aIn = (ArmoredInputStream) in; + // it is ascii armored + Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); + + if (aIn.isClearText()) { + // a cleartext signature, verify it with the other method + return verifyCleartextSignature(aIn, 0); + } else { + // else: ascii armored encryption! go on... + return decryptVerify(in, 0); + } + } else { + return decryptVerify(in, 0); } - // else: ascii armored encryption! go on... } - - return decryptVerify(in, 0); } catch (PGPException e) { Log.d(Constants.TAG, "PGPException", e); OperationLog log = new OperationLog(); @@ -205,7 +227,7 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC, indent); indent += 1; - PGPObjectFactory pgpF = new PGPObjectFactory(in, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in); PGPEncryptedDataList enc; Object o = pgpF.nextObject(); @@ -234,6 +256,25 @@ public class PgpDecryptVerify extends BaseOperation { boolean symmetricPacketFound = false; boolean anyPacketFound = false; + // If the input stream is armored, and there is a charset specified, take a note for later + // https://tools.ietf.org/html/rfc4880#page56 + String charset = null; + if (in instanceof ArmoredInputStream) { + ArmoredInputStream aIn = (ArmoredInputStream) in; + if (aIn.getArmorHeaders() != null) { + for (String header : aIn.getArmorHeaders()) { + String[] pieces = header.split(":", 2); + if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) { + charset = pieces[1].trim(); + break; + } + } + if (charset != null) { + log.add(LogType.MSG_DC_CHARSET, indent, charset); + } + } + } + // go through all objects and find one we can decrypt while (it.hasNext()) { Object obj = it.next(); @@ -257,19 +298,19 @@ public class PgpDecryptVerify extends BaseOperation { ); } catch (ProviderHelper.NotFoundException e) { // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } if (secretKeyRing == null) { // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } // get subkey which has been used for this encryption packet secretEncryptionKey = secretKeyRing.getSecretKey(subKeyId); if (secretEncryptionKey == null) { // should actually never happen, so no need to be more specific. - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } @@ -283,7 +324,7 @@ public class PgpDecryptVerify extends BaseOperation { if (!mAllowedKeyIds.contains(masterKeyId)) { // this key is in our db, but NOT allowed! // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NOT_ALLOWED, indent +1); + log.add(LogType.MSG_DC_ASKIP_NOT_ALLOWED, indent + 1); continue; } } @@ -298,15 +339,15 @@ public class PgpDecryptVerify extends BaseOperation { try { // returns "" if key has no passphrase mPassphrase = getCachedPassphrase(subKeyId); - log.add(LogType.MSG_DC_PASS_CACHED, indent +1); + log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); } catch (PassphraseCacheInterface.NoSecretKeyException e) { - log.add(LogType.MSG_DC_ERROR_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } // if passphrase was not cached, return here indicating that a passphrase is missing! if (mPassphrase == null) { - log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log); result.setKeyIdPassphraseNeeded(subKeyId); @@ -322,8 +363,8 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC_SYM, indent); - if (! mAllowSymmetricDecryption) { - log.add(LogType.MSG_DC_SYM_SKIP, indent +1); + if (!mAllowSymmetricDecryption) { + log.add(LogType.MSG_DC_SYM_SKIP, indent + 1); continue; } @@ -338,7 +379,7 @@ public class PgpDecryptVerify extends BaseOperation { // if no passphrase is given, return here // indicating that a passphrase is missing! if (mPassphrase == null) { - log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE, log); } @@ -383,13 +424,13 @@ public class PgpDecryptVerify extends BaseOperation { updateProgress(R.string.progress_extracting_key, currentProgress, 100); try { - log.add(LogType.MSG_DC_UNLOCKING, indent +1); + log.add(LogType.MSG_DC_UNLOCKING, indent + 1); if (!secretEncryptionKey.unlock(mPassphrase)) { - log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } } catch (PgpGeneralException e) { - log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent +1); + log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -401,7 +442,7 @@ public class PgpDecryptVerify extends BaseOperation { = secretEncryptionKey.getDecryptorFactory(mDecryptedSessionKey); clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); } catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) { - log.add(LogType.MSG_DC_PENDING_NFC, indent +1); + log.add(LogType.MSG_DC_PENDING_NFC, indent + 1); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_NFC, log); result.setNfcState(secretEncryptionKey.getKeyId(), e.encryptedSessionKey, mPassphrase); @@ -412,11 +453,11 @@ public class PgpDecryptVerify extends BaseOperation { // If we didn't find any useful data, error out // no packet has been found where we have the corresponding secret key in our db log.add( - anyPacketFound ? LogType.MSG_DC_ERROR_NO_KEY : LogType.MSG_DC_ERROR_NO_DATA, indent +1); + anyPacketFound ? LogType.MSG_DC_ERROR_NO_KEY : LogType.MSG_DC_ERROR_NO_DATA, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPObjectFactory plainFact = new PGPObjectFactory(clear, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); int signatureIndex = -1; @@ -427,25 +468,27 @@ public class PgpDecryptVerify extends BaseOperation { indent += 1; if (dataChunk instanceof PGPCompressedData) { - log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent +1); + log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1); currentProgress += 2; updateProgress(R.string.progress_decompressing_data, currentProgress, 100); PGPCompressedData compressedData = (PGPCompressedData) dataChunk; - PGPObjectFactory fact = new PGPObjectFactory(compressedData.getDataStream(), new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory fact = new JcaPGPObjectFactory(compressedData.getDataStream()); dataChunk = fact.nextObject(); plainFact = fact; } PGPOnePassSignature signature = null; if (dataChunk instanceof PGPOnePassSignatureList) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1); currentProgress += 2; updateProgress(R.string.progress_processing_signature, currentProgress, 100); PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; + // NOTE: following code is similar to processSignature, but for PGPOnePassSignature + // go through all signatures // and find out for which signature we have a key in our database for (int i = 0; i < sigList.size(); ++i) { @@ -491,7 +534,7 @@ public class PgpDecryptVerify extends BaseOperation { OpenPgpMetadata metadata; if (dataChunk instanceof PGPLiteralData) { - log.add(LogType.MSG_DC_CLEAR_DATA, indent +1); + log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1); indent += 2; currentProgress += 4; updateProgress(R.string.progress_decrypting, currentProgress, 100); @@ -533,12 +576,12 @@ public class PgpDecryptVerify extends BaseOperation { literalData.getModificationTime().getTime(), originalSize); - if ( ! originalFilename.equals("")) { + if (!originalFilename.equals("")) { log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename); } - log.add(LogType.MSG_DC_CLEAR_META_MIME, indent +1, + log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType); - log.add(LogType.MSG_DC_CLEAR_META_TIME, indent +1, + log.add(LogType.MSG_DC_CLEAR_META_TIME, indent + 1, new Date(literalData.getModificationTime().getTime()).toString()); if (originalSize != 0) { log.add(LogType.MSG_DC_CLEAR_META_SIZE, indent + 1, @@ -550,6 +593,7 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC_OK_META_ONLY, indent); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setCharset(charset); result.setDecryptMetadata(metadata); return result; } @@ -572,7 +616,9 @@ public class PgpDecryptVerify extends BaseOperation { int length; byte[] buffer = new byte[1 << 16]; while ((length = dataIn.read(buffer)) > 0) { - mOutStream.write(buffer, 0, length); + if (mOutStream != null) { + mOutStream.write(buffer, 0, length); + } // update signature buffer if signature is also present if (signature != null) { @@ -606,9 +652,9 @@ public class PgpDecryptVerify extends BaseOperation { // Verify signature and check binding signatures boolean validSignature = signature.verify(messageSignature); if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); } signatureResultBuilder.setValidSignature(validSignature); } @@ -647,6 +693,7 @@ public class PgpDecryptVerify extends BaseOperation { new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setDecryptMetadata(metadata); result.setSignatureResult(signatureResultBuilder.build()); + result.setCharset(charset); return result; } @@ -669,7 +716,7 @@ public class PgpDecryptVerify extends BaseOperation { ByteArrayOutputStream out = new ByteArrayOutputStream(); - updateProgress(R.string.progress_done, 0, 100); + updateProgress(R.string.progress_reading_data, 0, 100); ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); int lookAhead = readInputLine(lineOut, aIn); @@ -689,10 +736,12 @@ public class PgpDecryptVerify extends BaseOperation { out.close(); byte[] clearText = out.toByteArray(); - mOutStream.write(clearText); + if (mOutStream != null) { + mOutStream.write(clearText); + } updateProgress(R.string.progress_processing_signature, 60, 100); - PGPObjectFactory pgpFact = new PGPObjectFactory(aIn, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn); PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); if (sigList == null) { @@ -700,45 +749,7 @@ public class PgpDecryptVerify extends BaseOperation { return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - CanonicalizedPublicKeyRing signingRing = null; - CanonicalizedPublicKey signingKey = null; - int signatureIndex = -1; - - // go through all signatures - // and find out for which signature we have a key in our database - for (int i = 0; i < sigList.size(); ++i) { - try { - long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) - ); - signingKey = signingRing.getPublicKey(sigKeyId); - signatureIndex = i; - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found, trying next signature..."); - } - } - - PGPSignature signature = null; - - if (signingKey != null) { - // key found in our database! - signature = sigList.get(signatureIndex); - - signatureResultBuilder.initValid(signingRing, signingKey); - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); - } else { - // no key in our database -> return "unknown pub key" status including the first key id - if (!sigList.isEmpty()) { - signatureResultBuilder.setSignatureAvailable(true); - signatureResultBuilder.setKnownKey(false); - signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); - } - } + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); if (signature != null) { try { @@ -786,6 +797,134 @@ public class PgpDecryptVerify extends BaseOperation { return result; } + private DecryptVerifyResult verifyDetachedSignature(InputStream in, int indent) + throws IOException, PGPException { + + OperationLog log = new OperationLog(); + + OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); + // detached signatures are never encrypted + signatureResultBuilder.setSignatureOnly(true); + + updateProgress(R.string.progress_processing_signature, 0, 100); + InputStream detachedSigIn = new ByteArrayInputStream(mDetachedSignature); + detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn); + + PGPSignatureList sigList; + Object o = pgpFact.nextObject(); + if (o instanceof PGPCompressedData) { + PGPCompressedData c1 = (PGPCompressedData) o; + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + sigList = (PGPSignatureList) pgpFact.nextObject(); + } else if (o instanceof PGPSignatureList) { + sigList = (PGPSignatureList) o; + } else { + log.add(LogType.MSG_DC_ERROR_INVALID_SIGLIST, 0); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + + if (signature != null) { + updateProgress(R.string.progress_reading_data, 60, 100); + + ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100); + long alreadyWritten = 0; + long wholeSize = mData.getSize() - mData.getStreamPosition(); + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + if (mOutStream != null) { + mOutStream.write(buffer, 0, length); + } + + // update signature buffer if signature is also present + signature.update(buffer, 0, length); + + alreadyWritten += length; + if (wholeSize > 0) { + long progress = 100 * alreadyWritten / wholeSize; + // stop at 100% for wrong file sizes... + if (progress > 100) { + progress = 100; + } + progressScaler.setProgress((int) progress, 100); + } else { + // TODO: slow annealing to fake a progress? + } + } + + updateProgress(R.string.progress_verifying_signature, 90, 100); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); + + // these are not cleartext signatures! + signatureResultBuilder.setSignatureOnly(false); + + // Verify signature and check binding signatures + boolean validSignature = signature.verify(); + if (validSignature) { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); + } else { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); + } + signatureResultBuilder.setValidSignature(validSignature); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_DC_OK, indent); + + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setSignatureResult(signatureResultBuilder.build()); + return result; + } + + private PGPSignature processPGPSignatureList(PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder) throws PGPException { + CanonicalizedPublicKeyRing signingRing = null; + CanonicalizedPublicKey signingKey = null; + int signatureIndex = -1; + + // go through all signatures + // and find out for which signature we have a key in our database + for (int i = 0; i < sigList.size(); ++i) { + try { + long sigKeyId = sigList.get(i).getKeyID(); + signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) + ); + signingKey = signingRing.getPublicKey(sigKeyId); + signatureIndex = i; + } catch (ProviderHelper.NotFoundException e) { + Log.d(Constants.TAG, "key not found, trying next signature..."); + } + } + + PGPSignature signature = null; + + if (signingKey != null) { + // key found in our database! + signature = sigList.get(signatureIndex); + + signatureResultBuilder.initValid(signingRing, signingKey); + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); + } else { + // no key in our database -> return "unknown pub key" status including the first key id + if (!sigList.isEmpty()) { + signatureResultBuilder.setSignatureAvailable(true); + signatureResultBuilder.setKnownKey(false); + signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); + } + } + + return signature; + } + /** * Mostly taken from ClearSignedFileProcessor in Bouncy Castle */ @@ -807,7 +946,7 @@ public class PgpDecryptVerify extends BaseOperation { while ((ch = fIn.read()) >= 0) { bOut.write(ch); if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); + lookAhead = readPastEOL(bOut, ch, fIn); break; } } @@ -824,7 +963,7 @@ public class PgpDecryptVerify extends BaseOperation { do { bOut.write(ch); if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); + lookAhead = readPastEOL(bOut, ch, fIn); break; } } while ((ch = fIn.read()) >= 0); @@ -836,7 +975,7 @@ public class PgpDecryptVerify extends BaseOperation { return lookAhead; } - private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) + private static int readPastEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) throws IOException { int lookAhead = fIn.read(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 4bab7f2b9..aebb52a03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -135,7 +135,7 @@ public class PgpKeyOperation { public PgpKeyOperation(Progressable progress) { super(); if (progress != null) { - mProgress = new Stack<Progressable>(); + mProgress = new Stack<>(); mProgress.push(progress); } } @@ -288,13 +288,11 @@ public class PgpKeyOperation { // build new key pair return new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - } catch(NoSuchProviderException e) { + } catch(NoSuchProviderException | InvalidAlgorithmParameterException e) { throw new RuntimeException(e); } catch(NoSuchAlgorithmException e) { log.add(LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent); return null; - } catch(InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); } catch(PGPException e) { Log.e(Constants.TAG, "internal pgp error", e); log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent); @@ -389,6 +387,9 @@ public class PgpKeyOperation { * with a passphrase fails, the operation will fail with an unlocking error. More specific * handling of errors should be done in UI code! * + * If the passphrase is null, only a restricted subset of operations will be available, + * namely stripping of subkeys and changing the protection mode of dummy keys. + * */ public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, String passphrase) { @@ -429,6 +430,11 @@ public class PgpKeyOperation { return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); } + // If we have no passphrase, only allow restricted operation + if (passphrase == null) { + return internalRestricted(sKR, saveParcel, log); + } + // read masterKeyFlags, and use the same as before. // since this is the master key, this contains at least CERTIFY_OTHER PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); @@ -496,7 +502,7 @@ public class PgpKeyOperation { @SuppressWarnings("unchecked") Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId); if (it != null) { - for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) { + for (PGPSignature cert : new IterableIterator<>(it)) { if (cert.getKeyID() != masterPublicKey.getKeyID()) { // foreign certificate?! error error error log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent); @@ -715,6 +721,27 @@ public class PgpKeyOperation { return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); } + if (change.mDummyStrip || change.mDummyDivert != null) { + // IT'S DANGEROUS~ + // no really, it is. this operation irrevocably removes the private key data from the key + if (change.mDummyStrip) { + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); + } else { + // the serial number must be 16 bytes in length + if (change.mDummyDivert.length != 16) { + log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + } + sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); + } + + // This doesn't concern us any further + if (!change.mRecertify && (change.mExpiry == null && change.mFlags == null)) { + continue; + } + // expiry must not be in the past if (change.mExpiry != null && change.mExpiry != 0 && new Date(change.mExpiry*1000).before(new Date())) { @@ -805,30 +832,6 @@ public class PgpKeyOperation { } subProgressPop(); - // 4c. For each subkey to be stripped... do so - subProgressPush(65, 70); - for (int i = 0; i < saveParcel.mStripSubKeys.size(); i++) { - - progress(R.string.progress_modify_subkeystrip, (i-1) * (100 / saveParcel.mStripSubKeys.size())); - long strip = saveParcel.mStripSubKeys.get(i); - log.add(LogType.MSG_MF_SUBKEY_STRIP, - indent, KeyFormattingUtils.convertKeyIdToHex(strip)); - - PGPSecretKey sKey = sKR.getSecretKey(strip); - if (sKey == null) { - log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, - indent+1, KeyFormattingUtils.convertKeyIdToHex(strip)); - return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); - } - - // IT'S DANGEROUS~ - // no really, it is. this operation irrevocably removes the private key data from the key - sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); - sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); - - } - subProgressPop(); - // 5. Generate and add new subkeys subProgressPush(70, 90); for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) { @@ -937,6 +940,73 @@ public class PgpKeyOperation { } + /** This method does the actual modifications in a keyring just like internal, except it + * supports only the subset of operations which require no passphrase, and will error + * otherwise. + */ + private PgpEditKeyResult internalRestricted(PGPSecretKeyRing sKR, SaveKeyringParcel saveParcel, + OperationLog log) { + + int indent = 1; + + progress(R.string.progress_modify, 0); + + // Make sure the saveParcel includes only operations available without passphrae! + if (!saveParcel.isRestrictedOnly()) { + log.add(LogType.MSG_MF_ERROR_RESTRICTED, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + + // Check if we were cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null); + } + + // The only operation we can do here: + // 4a. Strip secret keys, or change their protection mode (stripped/divert-to-card) + subProgressPush(50, 60); + for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) { + + progress(R.string.progress_modify_subkeychange, (i - 1) * (100 / saveParcel.mChangeSubKeys.size())); + SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i); + log.add(LogType.MSG_MF_SUBKEY_CHANGE, + indent, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + + PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId); + if (sKey == null) { + log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + + if (change.mDummyStrip || change.mDummyDivert != null) { + // IT'S DANGEROUS~ + // no really, it is. this operation irrevocably removes the private key data from the key + if (change.mDummyStrip) { + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); + } else { + // the serial number must be 16 bytes in length + if (change.mDummyDivert.length != 16) { + log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), change.mDummyDivert); + } + sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); + } + + } + + // And we're done! + progress(R.string.progress_done, 100); + log.add(LogType.MSG_MF_SUCCESS, indent); + return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR)); + + } + + private static PGPSecretKeyRing applyNewUnlock( PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 3c3bcc890..060db96b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -78,9 +79,11 @@ public class PgpSignEncrypt extends BaseOperation { private int mSignatureHashAlgorithm; private String mSignaturePassphrase; private long mAdditionalEncryptId; - private boolean mCleartextInput; + private boolean mCleartextSignature; + private boolean mDetachedSignature; private String mOriginalFilename; private boolean mFailOnMissingEncryptionKeyIds; + private String mCharset; private byte[] mNfcSignedHash = null; private Date mNfcCreationTimestamp = null; @@ -113,11 +116,13 @@ public class PgpSignEncrypt extends BaseOperation { this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm; this.mSignaturePassphrase = builder.mSignaturePassphrase; this.mAdditionalEncryptId = builder.mAdditionalEncryptId; - this.mCleartextInput = builder.mCleartextInput; + this.mCleartextSignature = builder.mCleartextSignature; + this.mDetachedSignature = builder.mDetachedSignature; this.mNfcSignedHash = builder.mNfcSignedHash; this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp; this.mOriginalFilename = builder.mOriginalFilename; this.mFailOnMissingEncryptionKeyIds = builder.mFailOnMissingEncryptionKeyIds; + this.mCharset = builder.mCharset; } public static class Builder { @@ -140,11 +145,13 @@ public class PgpSignEncrypt extends BaseOperation { private int mSignatureHashAlgorithm = 0; private String mSignaturePassphrase = null; private long mAdditionalEncryptId = Constants.key.none; - private boolean mCleartextInput = false; + private boolean mCleartextSignature = false; + private boolean mDetachedSignature = false; private String mOriginalFilename = ""; private byte[] mNfcSignedHash = null; private Date mNfcCreationTimestamp = null; private boolean mFailOnMissingEncryptionKeyIds = false; + private String mCharset = null; public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, InputData data, OutputStream outStream) { @@ -211,6 +218,11 @@ public class PgpSignEncrypt extends BaseOperation { return this; } + public Builder setCharset(String charset) { + mCharset = charset; + return this; + } + /** * Also encrypt with the signing keyring * @@ -222,14 +234,13 @@ public class PgpSignEncrypt extends BaseOperation { return this; } - /** - * TODO: test this option! - * - * @param cleartextInput - * @return - */ - public Builder setCleartextInput(boolean cleartextInput) { - mCleartextInput = cleartextInput; + public Builder setCleartextSignature(boolean cleartextSignature) { + mCleartextSignature = cleartextSignature; + return this; + } + + public Builder setDetachedSignature(boolean detachedSignature) { + mDetachedSignature = detachedSignature; return this; } @@ -283,6 +294,10 @@ public class PgpSignEncrypt extends BaseOperation { if (mVersionHeader != null) { armorOut.setHeader("Version", mVersionHeader); } + // if we have a charset, put it in the header + if (mCharset != null) { + armorOut.setHeader("Charset", mCharset); + } out = armorOut; } else { out = mOutStream; @@ -408,7 +423,7 @@ public class PgpSignEncrypt extends BaseOperation { updateProgress(R.string.progress_preparing_signature, 4, 100); try { - boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption; + boolean cleartext = mCleartextSignature && mEnableAsciiArmorOutput && !enableEncryption; signatureGenerator = signingKey.getSignatureGenerator( mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp); } catch (PgpGeneralException e) { @@ -424,6 +439,10 @@ public class PgpSignEncrypt extends BaseOperation { OutputStream encryptionOut = null; BCPGOutputStream bcpgOut; + ByteArrayOutputStream detachedByteOut = null; + ArmoredOutputStream detachedArmorOut = null; + BCPGOutputStream detachedBcpgOut = null; + try { if (enableEncryption) { @@ -452,7 +471,7 @@ public class PgpSignEncrypt extends BaseOperation { PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); char literalDataFormatTag; - if (mCleartextInput) { + if (mCleartextSignature) { literalDataFormatTag = PGPLiteralData.UTF8; } else { literalDataFormatTag = PGPLiteralData.BINARY; @@ -482,7 +501,7 @@ public class PgpSignEncrypt extends BaseOperation { literalGen.close(); indent -= 1; - } else if (enableSignature && mCleartextInput && mEnableAsciiArmorOutput) { + } else if (enableSignature && mCleartextSignature && mEnableAsciiArmorOutput) { /* cleartext signature: sign-only of ascii text */ updateProgress(R.string.progress_signing, 8, 100); @@ -517,11 +536,48 @@ public class PgpSignEncrypt extends BaseOperation { armorOut.endClearText(); pOut = new BCPGOutputStream(armorOut); - } else if (enableSignature && !mCleartextInput) { + } else if (enableSignature && mDetachedSignature) { + /* detached signature */ + + updateProgress(R.string.progress_signing, 8, 100); + log.add(LogType.MSG_SE_SIGNING, indent); + + InputStream in = mData.getInputStream(); + + // handle output stream separately for detached signatures + detachedByteOut = new ByteArrayOutputStream(); + OutputStream detachedOut = detachedByteOut; + if (mEnableAsciiArmorOutput) { + detachedArmorOut = new ArmoredOutputStream(detachedOut); + if (mVersionHeader != null) { + detachedArmorOut.setHeader("Version", mVersionHeader); + } + + detachedOut = detachedArmorOut; + } + detachedBcpgOut = new BCPGOutputStream(detachedOut); + + long alreadyWritten = 0; + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + // no output stream is written, no changed to original data! + + signatureGenerator.update(buffer, 0, length); + + alreadyWritten += length; + if (mData.getSize() > 0) { + long progress = 100 * alreadyWritten / mData.getSize(); + progressScaler.setProgress((int) progress, 100); + } + } + + pOut = null; + } else if (enableSignature && !mCleartextSignature && !mDetachedSignature) { /* sign-only binary (files/data stream) */ updateProgress(R.string.progress_signing, 8, 100); - log.add(LogType.MSG_SE_ENCRYPTING, indent); + log.add(LogType.MSG_SE_SIGNING, indent); InputStream in = mData.getInputStream(); @@ -556,13 +612,18 @@ public class PgpSignEncrypt extends BaseOperation { literalGen.close(); } else { pOut = null; + // TODO: Is this log right? log.add(LogType.MSG_SE_CLEARSIGN_ONLY, indent); } if (enableSignature) { updateProgress(R.string.progress_generating_signature, 95, 100); try { - signatureGenerator.generate().encode(pOut); + if (detachedBcpgOut != null) { + signatureGenerator.generate().encode(detachedBcpgOut); + } else { + signatureGenerator.generate().encode(pOut); + } } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed log.add(LogType.MSG_SE_PENDING_NFC, indent); @@ -571,27 +632,38 @@ public class PgpSignEncrypt extends BaseOperation { // Note that the checked key here is the master key, not the signing key // (although these are always the same on Yubikeys) result.setNfcData(mSignatureSubKeyId, e.hashToSign, e.hashAlgo, e.creationTimestamp, mSignaturePassphrase); - Log.d(Constants.TAG, "e.hashToSign"+ Hex.toHexString(e.hashToSign)); + Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign)); return result; } } // closing outputs // NOTE: closing needs to be done in the correct order! - // TODO: closing bcpgOut and pOut??? - if (enableEncryption) { - if (enableCompression) { + if (encryptionOut != null) { + if (compressGen != null) { compressGen.close(); } encryptionOut.close(); } - if (mEnableAsciiArmorOutput) { + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (armorOut != null) { armorOut.close(); } - - out.close(); - mOutStream.close(); + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (detachedArmorOut != null) { + detachedArmorOut.close(); + } + // Also closes detachedBcpgOut + if (detachedByteOut != null) { + detachedByteOut.close(); + } + if (out != null) { + out.close(); + } + if (mOutStream != null) { + mOutStream.close(); + } } catch (SignatureException e) { log.add(LogType.MSG_SE_ERROR_SIG, indent); @@ -607,10 +679,22 @@ public class PgpSignEncrypt extends BaseOperation { updateProgress(R.string.progress_done, 100, 100); log.add(LogType.MSG_SE_OK, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_OK, log); - + SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_OK, log); + if (detachedByteOut != null) { + try { + detachedByteOut.flush(); + detachedByteOut.close(); + } catch (IOException e) { + // silently catch + } + result.setDetachedSignature(detachedByteOut.toByteArray()); + } + return result; } + /** + * Remove whitespaces on line endings + */ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 04fb955fa..af85bd878 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -445,7 +445,7 @@ public class UncachedKeyRing { } } - ArrayList<String> processedUserIds = new ArrayList<String>(); + ArrayList<String> processedUserIds = new ArrayList<>(); for (byte[] rawUserId : new IterableIterator<byte[]>(masterKey.getRawUserIDs())) { String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); @@ -470,7 +470,7 @@ public class UncachedKeyRing { @SuppressWarnings("unchecked") Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForID(rawUserId); if (signaturesIt != null) { - for (PGPSignature zert : new IterableIterator<PGPSignature>(signaturesIt)) { + for (PGPSignature zert : new IterableIterator<>(signaturesIt)) { WrappedSignature cert = new WrappedSignature(zert); long certId = cert.getKeyId(); @@ -635,7 +635,7 @@ public class UncachedKeyRing { @SuppressWarnings("unchecked") Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute); if (signaturesIt != null) { - for (PGPSignature zert : new IterableIterator<PGPSignature>(signaturesIt)) { + for (PGPSignature zert : new IterableIterator<>(signaturesIt)) { WrappedSignature cert = new WrappedSignature(zert); long certId = cert.getKeyId(); @@ -778,7 +778,7 @@ public class UncachedKeyRing { } // Keep track of ids we encountered so far - Set<Long> knownIds = new HashSet<Long>(); + Set<Long> knownIds = new HashSet<>(); // Process all keys for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(ring.getPublicKeys())) { @@ -1042,7 +1042,7 @@ public class UncachedKeyRing { } // remember which certs we already added. this is cheaper than semantic deduplication - Set<byte[]> certs = new TreeSet<byte[]>(new Comparator<byte[]>() { + Set<byte[]> certs = new TreeSet<>(new Comparator<byte[]>() { public int compare(byte[] left, byte[] right) { // check for length equality if (left.length != right.length) { @@ -1124,7 +1124,7 @@ public class UncachedKeyRing { if (signaturesIt == null) { continue; } - for (PGPSignature cert : new IterableIterator<PGPSignature>(signaturesIt)) { + for (PGPSignature cert : new IterableIterator<>(signaturesIt)) { // Don't merge foreign stuff into secret keys if (cert.getKeyID() != masterKeyId && isSecret()) { continue; @@ -1149,7 +1149,7 @@ public class UncachedKeyRing { if (signaturesIt == null) { continue; } - for (PGPSignature cert : new IterableIterator<PGPSignature>(signaturesIt)) { + for (PGPSignature cert : new IterableIterator<>(signaturesIt)) { // Don't merge foreign stuff into secret keys if (cert.getKeyID() != masterKeyId && isSecret()) { continue; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 9e3528515..0fe1ccdb6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ECPublicBCPGKey; import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; @@ -136,7 +135,7 @@ public class UncachedPublicKey { continue; } - for (PGPSignature sig : new IterableIterator<PGPSignature>(signaturesIt)) { + for (PGPSignature sig : new IterableIterator<>(signaturesIt)) { try { // if this is a revocation, this is not the user id @@ -200,7 +199,7 @@ public class UncachedPublicKey { } public ArrayList<String> getUnorderedUserIds() { - ArrayList<String> userIds = new ArrayList<String>(); + ArrayList<String> userIds = new ArrayList<>(); for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) { // use our decoding method userIds.add(Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId)); @@ -209,7 +208,7 @@ public class UncachedPublicKey { } public ArrayList<byte[]> getUnorderedRawUserIds() { - ArrayList<byte[]> userIds = new ArrayList<byte[]>(); + ArrayList<byte[]> userIds = new ArrayList<>(); for (byte[] userId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) { userIds.add(userId); } @@ -217,7 +216,7 @@ public class UncachedPublicKey { } public ArrayList<WrappedUserAttribute> getUnorderedUserAttributes() { - ArrayList<WrappedUserAttribute> userAttributes = new ArrayList<WrappedUserAttribute>(); + ArrayList<WrappedUserAttribute> userAttributes = new ArrayList<>(); for (PGPUserAttributeSubpacketVector userAttribute : new IterableIterator<PGPUserAttributeSubpacketVector>(mPublicKey.getUserAttributes())) { userAttributes.add(new WrappedUserAttribute(userAttribute)); @@ -305,26 +304,56 @@ public class UncachedPublicKey { * * Note that this method has package visiblity because it is used in test * cases. Certificates of UncachedPublicKey instances can NOT be assumed to - * be verified, so the result of this method should not be used in other - * places! + * be verified or even by the correct key, so the result of this method + * should never be used in other places! */ @SuppressWarnings("unchecked") Integer getKeyUsage() { if (mCacheUsage == null) { + PGPSignature mostRecentSig = null; for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignatures())) { if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) { continue; } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + switch (sig.getSignatureType()) { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.SUBKEY_BINDING: + break; + // if this is not one of the above types, don't care + default: + continue; + } + + // If we have no sig yet, take the first we can get + if (mostRecentSig == null) { + mostRecentSig = sig; + continue; + } + + // If the new sig is less recent, skip it + if (mostRecentSig.getCreationTime().after(sig.getCreationTime())) { + continue; + } + + // Otherwise, note it down as the new "most recent" one + mostRecentSig = sig; + } + + // Initialize to 0 as cached but empty value, if there is no sig (can't happen + // for canonicalized keyring), or there is no KEY_FLAGS packet in the sig + mCacheUsage = 0; + if (mostRecentSig != null) { + // If a mostRecentSig has been found, (cache and) return its flags + PGPSignatureSubpacketVector hashed = mostRecentSig.getHashedSubPackets(); if (hashed != null && hashed.getSubpacket(SignatureSubpacketTags.KEY_FLAGS) != null) { - // init if at least one key flag subpacket has been found - if (mCacheUsage == null) { - mCacheUsage = 0; - } - mCacheUsage |= hashed.getKeyFlags(); + mCacheUsage = hashed.getKeyFlags(); } } + } return mCacheUsage; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index cb03970e2..ade075d55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -36,7 +36,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; -import java.security.SignatureException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -80,7 +79,7 @@ public class WrappedSignature { } public ArrayList<WrappedSignature> getEmbeddedSignatures() { - ArrayList<WrappedSignature> sigs = new ArrayList<WrappedSignature>(); + ArrayList<WrappedSignature> sigs = new ArrayList<>(); if (!mSig.hasSubpackets()) { return sigs; } @@ -255,7 +254,7 @@ public class WrappedSignature { } public HashMap<String,String> getNotation() { - HashMap<String,String> result = new HashMap<String,String>(); + HashMap<String,String> result = new HashMap<>(); // If there is any notation data if (mSig.getHashedSubPackets() != null diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 29b9c5f9f..72475472e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -248,7 +248,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_UNIFIED: case KEY_RINGS_FIND_BY_EMAIL: case KEY_RINGS_FIND_BY_SUBKEY: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID); @@ -432,7 +432,7 @@ public class KeychainProvider extends ContentProvider { } case KEY_RING_KEYS: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK); @@ -460,7 +460,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_USER_IDS: case KEY_RING_USER_IDS: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id"); projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID); projectionMap.put(UserPackets.TYPE, Tables.USER_PACKETS + "." + UserPackets.TYPE); @@ -507,7 +507,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_PUBLIC: case KEY_RING_PUBLIC: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id"); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); @@ -525,7 +525,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_SECRET: case KEY_RING_SECRET: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id"); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); @@ -543,7 +543,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RING_CERTS: case KEY_RING_CERTS_SPECIFIC: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); + HashMap<String, String> projectionMap = new HashMap<>(); projectionMap.put(Certs._ID, Tables.CERTS + ".oid AS " + Certs._ID); projectionMap.put(Certs.MASTER_KEY_ID, Tables.CERTS + "." + Certs.MASTER_KEY_ID); projectionMap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index c3990229d..a229f454f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -170,7 +170,7 @@ public class ProviderHelper { Cursor cursor = mContentResolver.query(uri, proj, selection, null, null); try { - HashMap<String, Object> result = new HashMap<String, Object>(proj.length); + HashMap<String, Object> result = new HashMap<>(proj.length); if (cursor != null && cursor.moveToFirst()) { int pos = 0; for (String p : proj) { @@ -221,7 +221,7 @@ public class ProviderHelper { }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); try { - LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<CanonicalizedPublicKey>(); + LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<>(); if (cursor != null && cursor.moveToFirst()) do { long masterKeyId = cursor.getLong(0); @@ -350,7 +350,7 @@ public class ProviderHelper { mIndent += 1; // save all keys and userIds included in keyRing object in database - operations = new ArrayList<ContentProviderOperation>(); + operations = new ArrayList<>(); log(LogType.MSG_IP_INSERT_KEYRING); { // insert keyring @@ -440,7 +440,7 @@ public class ProviderHelper { // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. - List<UserPacketItem> uids = new ArrayList<UserPacketItem>(); + List<UserPacketItem> uids = new ArrayList<>(); if (trustedKeys.size() == 0) { log(LogType.MSG_IP_UID_CLASSIFYING_ZERO); @@ -460,7 +460,7 @@ public class ProviderHelper { log(LogType.MSG_IP_UID_PROCESSING, userId); mIndent += 1; // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator<WrappedSignature>( + for (WrappedSignature cert : new IterableIterator<>( masterKey.getSignaturesForRawId(rawUserId))) { long certId = cert.getKeyId(); // self signature @@ -560,7 +560,7 @@ public class ProviderHelper { } mIndent += 1; // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator<WrappedSignature>( + for (WrappedSignature cert : new IterableIterator<>( masterKey.getSignaturesForUserAttribute(userAttribute))) { long certId = cert.getKeyId(); // self signature @@ -712,10 +712,14 @@ public class ProviderHelper { boolean isPrimary = false; boolean isRevoked = false; WrappedSignature selfCert; - LongSparseArray<WrappedSignature> trustedCerts = new LongSparseArray<WrappedSignature>(); + LongSparseArray<WrappedSignature> trustedCerts = new LongSparseArray<>(); @Override public int compareTo(UserPacketItem o) { + // revoked keys always come last! + if (isRevoked != o.isRevoked) { + return isRevoked ? 1 : -1; + } // if one is a user id, but the other isn't, the user id always comes first. // we compare for null values here, so != is the correct operator! // noinspection NumberEquality @@ -726,10 +730,6 @@ public class ProviderHelper { if (isPrimary != o.isPrimary) { return isPrimary ? -1 : 1; } - // revoked keys always come last! - if (isRevoked != o.isRevoked) { - return isRevoked ? 1 : -1; - } return 0; } } @@ -1075,7 +1075,7 @@ public class ProviderHelper { // No keys existing might be a legitimate option, we write an empty file in that case cursor.moveToFirst(); ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); cache.writeCache(cursor.getCount(), new Iterator<ParcelableKeyRing>() { ParcelableKeyRing ring; @@ -1137,7 +1137,7 @@ public class ProviderHelper { // No keys existing might be a legitimate option, we write an empty file in that case cursor.moveToFirst(); ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(mContext, "consolidate_public.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); cache.writeCache(cursor.getCount(), new Iterator<ParcelableKeyRing>() { ParcelableKeyRing ring; @@ -1220,9 +1220,9 @@ public class ProviderHelper { mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); ParcelableFileCache<ParcelableKeyRing> cacheSecret = - new ParcelableFileCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); ParcelableFileCache<ParcelableKeyRing> cachePublic = - new ParcelableFileCache<ParcelableKeyRing>(mContext, "consolidate_public.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); // Set flag that we have a cached consolidation here try { @@ -1380,7 +1380,7 @@ public class ProviderHelper { public ArrayList<String> getRegisteredApiApps() { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); - ArrayList<String> packageNames = new ArrayList<String>(); + ArrayList<String> packageNames = new ArrayList<>(); try { if (cursor != null) { int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); @@ -1485,7 +1485,7 @@ public class ProviderHelper { } public Set<Long> getAllKeyIdsForApp(Uri uri) { - Set<Long> keyIds = new HashSet<Long>(); + Set<Long> keyIds = new HashSet<>(); Cursor cursor = mContentResolver.query(uri, null, null, null, null); try { @@ -1505,7 +1505,7 @@ public class ProviderHelper { } public Set<String> getAllFingerprints(Uri uri) { - Set<String> fingerprints = new HashSet<String>(); + Set<String> fingerprints = new HashSet<>(); String[] projection = new String[]{KeyRings.FINGERPRINT}; Cursor cursor = mContentResolver.query(uri, projection, null, null, null); try { 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 a5813567a..d967931ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -85,9 +85,9 @@ public class OpenPgpService extends RemoteService { boolean missingUserIdsCheck = false; boolean duplicateUserIdsCheck = false; - ArrayList<Long> keyIds = new ArrayList<Long>(); - ArrayList<String> missingUserIds = new ArrayList<String>(); - ArrayList<String> duplicateUserIds = new ArrayList<String>(); + ArrayList<Long> keyIds = new ArrayList<>(); + ArrayList<String> missingUserIds = new ArrayList<>(); + ArrayList<String> duplicateUserIds = new ArrayList<>(); if (!noUserIdsCheck) { for (String email : encryptionUserIds) { // try to find the key for this specific email @@ -222,9 +222,10 @@ public class OpenPgpService extends RemoteService { } private Intent signImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings) { + ParcelFileDescriptor output, AccountSettings accSettings, + boolean cleartextSign) { try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); + boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); if (nfcSignedHash != null) { @@ -243,7 +244,12 @@ public class OpenPgpService extends RemoteService { // Get Input- and OutputStream from ParcelFileDescriptor InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + OutputStream os = null; + if (cleartextSign) { + // output stream only needed for cleartext signatures, + // detached signatures are returned as extra + os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + } try { long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); @@ -284,6 +290,8 @@ public class OpenPgpService extends RemoteService { inputData, os ); builder.setEnableAsciiArmorOutput(asciiArmor) + .setCleartextSignature(cleartextSign) + .setDetachedSignature(!cleartextSign) .setVersionHeader(PgpHelper.getVersionForHeader(this)) .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) .setSignatureMasterKeyId(accSettings.getKeyId()) @@ -291,9 +299,6 @@ public class OpenPgpService extends RemoteService { .setSignaturePassphrase(passphrase) .setNfcState(nfcSignedHash, nfcCreationDate); - // TODO: currently always assume cleartext input, no sign-only of binary currently! - builder.setCleartextInput(true); - // execute PGP operation! SignEncryptResult pgpResult = builder.build().execute(); @@ -313,20 +318,22 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { - // see end of method + Intent result = new Intent(); + if (!cleartextSign) { + result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature()); + } + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); } - } finally { is.close(); - os.close(); + if (os != null) { + os.close(); + } } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "signImpl", e); Intent result = new Intent(); @@ -444,7 +451,9 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { - // see end of method + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); @@ -454,10 +463,6 @@ public class OpenPgpService extends RemoteService { is.close(); os.close(); } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "encryptAndSignImpl", e); Intent result = new Intent(); @@ -476,13 +481,13 @@ public class OpenPgpService extends RemoteService { InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); OutputStream os; - if (decryptMetadataOnly) { + // output is optional, e.g., for verifying detached signatures + if (decryptMetadataOnly || output == null) { os = null; } else { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); } - Intent result = new Intent(); try { String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); long inputLength = is.available(); @@ -494,15 +499,17 @@ public class OpenPgpService extends RemoteService { byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); + byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE); + // allow only private keys associated with accounts of this app // no support for symmetric encryption builder.setPassphrase(passphrase) .setAllowSymmetricDecryption(false) .setAllowedKeyIds(allowedKeyIds) .setDecryptMetadataOnly(decryptMetadataOnly) - .setNfcState(nfcDecryptedSessionKey); + .setNfcState(nfcDecryptedSessionKey) + .setDetachedSignature(detachedSignature); - // TODO: currently does not support binary signed-only content DecryptVerifyResult pgpResult = builder.build().execute(); if (pgpResult.isPending()) { @@ -522,6 +529,7 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { + Intent result = new Intent(); OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); if (signatureResult != null) { @@ -557,6 +565,14 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); } } + + String charset = pgpResult.getCharset(); + if (charset != null) { + result.putExtra(OpenPgpApi.RESULT_CHARSET, charset); + } + + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); @@ -567,9 +583,6 @@ public class OpenPgpService extends RemoteService { os.close(); } } - - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "decryptAndVerifyImpl", e); Intent result = new Intent(); @@ -668,15 +681,16 @@ public class OpenPgpService extends RemoteService { // version code is required and needs to correspond to version code of service! // History of versions in org.openintents.openpgp.util.OpenPgpApi - // we support 3, 4, 5 + // we support 3, 4, 5, 6 if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 3 && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 4 - && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5) { + && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5 + && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 6) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n" + "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n" - + "supported API versions: 3, 4"); + + "supported API versions: 3, 4, 5, 6"); result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; @@ -718,8 +732,14 @@ public class OpenPgpService extends RemoteService { } String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings); + if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_SIGN.equals(action)) { + // DEPRECATED: same as ACTION_CLEARTEXT_SIGN + Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!"); + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, false); } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, accSettings, false); } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java index e71b52ccd..672f59285 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.net.Uri; import android.os.Binder; -import android.text.TextUtils; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.util.OpenPgpApi; @@ -216,9 +215,7 @@ public abstract class RemoteService extends Service { String[] callingPackages = getPackageManager().getPackagesForUid(uid); // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - + for (String currentPkg : callingPackages) { if (isPackageAllowed(currentPkg)) { return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index 7d77a989d..e5edd6a0f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.remote.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -28,7 +27,6 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.BaseActivity; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult; @@ -46,14 +44,18 @@ public class AccountSettingsActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.api_settings_save, new View.OnClickListener() { @Override public void onClick(View v) { - // "Done" save(); } + }, + new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } }); @@ -130,9 +132,4 @@ public class AccountSettingsActivity extends BaseActivity { } } - @Override - public void onBackPressed() { - save(); - super.onBackPressed(); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index d84a03698..e91482e28 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -22,8 +22,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java index 079b3065e..3b4cc654e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java @@ -21,19 +21,27 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.DrawerActivity; +import org.sufficientlysecure.keychain.ui.NavDrawerActivity; -public class AppsListActivity extends DrawerActivity { +public class AppsListActivity extends NavDrawerActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - activateDrawerNavigation(savedInstanceState); - } +// @Override +// protected void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// +// activateDrawerNavigation(savedInstanceState); +// } @Override - protected void initLayout() { + public void init(Bundle savedInstanceState) { + super.init(savedInstanceState); setContentView(R.layout.api_apps_list_activity); } + +// @Override +// protected void initLayout() { +// setContentView(R.layout.api_apps_list_activity); +// } + } 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 a9a7c75f5..cbc593b0a 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 @@ -22,7 +22,6 @@ import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -41,7 +40,6 @@ import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -108,234 +106,239 @@ public class RemoteServiceActivity extends BaseActivity { final Bundle extras = intent.getExtras(); - if (ACTION_REGISTER.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); - Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); + switch (action) { + case ACTION_REGISTER: { + final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); + Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); - setContentView(R.layout.api_remote_register_app); - initToolbar(); + setContentView(R.layout.api_remote_register_app); + initToolbar(); - mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); + mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_app_settings_fragment); - AppSettings settings = new AppSettings(packageName, packageSignature); - mAppSettingsFragment.setAppSettings(settings); + AppSettings settings = new AppSettings(packageName, packageSignature); + mAppSettingsFragment.setAppSettings(settings); - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_register_allow, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Allow + // Inflate a "Done"/"Cancel" custom action bar view + setFullScreenDialogTwoButtons( + R.string.api_register_allow, R.drawable.ic_check_white_24dp, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Allow - mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings()); + mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings()); - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.api_register_disallow, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Disallow - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); + // give data through for new service call + Intent resultData = extras.getParcelable(EXTRA_DATA); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); + } + }, R.string.api_register_disallow, R.drawable.ic_close_white_24dp, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Disallow + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } } - } - ); - } else if (ACTION_CREATE_ACCOUNT.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final String accName = extras.getString(EXTRA_ACC_NAME); + ); + break; + } + case ACTION_CREATE_ACCOUNT: { + final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + final String accName = extras.getString(EXTRA_ACC_NAME); - setContentView(R.layout.api_remote_create_account); - initToolbar(); + setContentView(R.layout.api_remote_create_account); + initToolbar(); - mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_account_settings_fragment); + mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_account_settings_fragment); - TextView text = (TextView) findViewById(R.id.api_remote_create_account_text); + TextView text = (TextView) findViewById(R.id.api_remote_create_account_text); - // update existing? - Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(packageName, accName); - AccountSettings settings = mProviderHelper.getApiAccountSettings(uri); - if (settings == null) { - // create new account - settings = new AccountSettings(accName); - mUpdateExistingAccount = false; + // update existing? + Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(packageName, accName); + AccountSettings settings = mProviderHelper.getApiAccountSettings(uri); + if (settings == null) { + // create new account + settings = new AccountSettings(accName); + mUpdateExistingAccount = false; - text.setText(R.string.api_create_account_text); - } else { - // update existing account - mUpdateExistingAccount = true; + text.setText(R.string.api_create_account_text); + } else { + // update existing account + mUpdateExistingAccount = true; - text.setText(R.string.api_update_account_text); - } - mAccSettingsFragment.setAccSettings(settings); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Save - - // 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); - } else { - if (mUpdateExistingAccount) { - Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName); - Uri accountUri = baseUri.buildUpon().appendEncodedPath(accName).build(); - mProviderHelper.updateApiAccount( - accountUri, - mAccSettingsFragment.getAccSettings()); + text.setText(R.string.api_update_account_text); + } + mAccSettingsFragment.setAccSettings(settings); + + // Inflate a "Done"/"Cancel" custom action bar view + setFullScreenDialogDoneClose(R.string.api_settings_save, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Save + + // 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); } else { - mProviderHelper.insertApiAccount( - KeychainContract.ApiAccounts.buildBaseUri(packageName), - mAccSettingsFragment.getAccSettings()); + if (mUpdateExistingAccount) { + Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName); + Uri accountUri = baseUri.buildUpon().appendEncodedPath(accName).build(); + mProviderHelper.updateApiAccount( + accountUri, + mAccSettingsFragment.getAccSettings()); + } else { + mProviderHelper.insertApiAccount( + KeychainContract.ApiAccounts.buildBaseUri(packageName), + mAccSettingsFragment.getAccSettings()); + } + + // give data through for new service call + Intent resultData = extras.getParcelable(EXTRA_DATA); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); } - - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + } + }, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Cancel + RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.finish(); } - } - }, R.string.api_settings_cancel, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } + }); + + break; + } + case ACTION_SELECT_PUB_KEYS: { + long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); + boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true); + ArrayList<String> missingUserIds = intent + .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); + ArrayList<String> dublicateUserIds = intent + .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + final SpannableString textIntro = new SpannableString( + noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids) + : getString(R.string.api_select_pub_keys_text) + ); + textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(textIntro); + + if (missingUserIds != null && missingUserIds.size() > 0) { + ssb.append("\n\n"); + ssb.append(getString(R.string.api_select_pub_keys_missing_text)); + ssb.append("\n"); + for (String userId : missingUserIds) { + SpannableString ss = new SpannableString(userId + "\n"); + ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(ss); } - ); - - } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { - long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true); - ArrayList<String> missingUserIds = intent - .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); - ArrayList<String> dublicateUserIds = intent - .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS); - - SpannableStringBuilder ssb = new SpannableStringBuilder(); - final SpannableString textIntro = new SpannableString( - noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids) - : getString(R.string.api_select_pub_keys_text) - ); - textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(textIntro); - - if (missingUserIds != null && missingUserIds.size() > 0) { - ssb.append("\n\n"); - ssb.append(getString(R.string.api_select_pub_keys_missing_text)); - ssb.append("\n"); - for (String userId : missingUserIds) { - SpannableString ss = new SpannableString(userId + "\n"); - ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(ss); } - } - if (dublicateUserIds != null && dublicateUserIds.size() > 0) { - ssb.append("\n\n"); - ssb.append(getString(R.string.api_select_pub_keys_dublicates_text)); - ssb.append("\n"); - for (String userId : dublicateUserIds) { - SpannableString ss = new SpannableString(userId + "\n"); - ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(ss); + if (dublicateUserIds != null && dublicateUserIds.size() > 0) { + ssb.append("\n\n"); + ssb.append(getString(R.string.api_select_pub_keys_dublicates_text)); + ssb.append("\n"); + for (String userId : dublicateUserIds) { + SpannableString ss = new SpannableString(userId + "\n"); + ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(ss); + } } - } - setContentView(R.layout.api_remote_select_pub_keys); - initToolbar(); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // add key ids to params Bundle for new request - Intent resultData = extras.getParcelable(EXTRA_DATA); - resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, - mSelectFragment.getSelectedMasterKeyIds()); - - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); + setContentView(R.layout.api_remote_select_pub_keys); + initToolbar(); + // Inflate a "Done"/"Cancel" custom action bar view + setFullScreenDialogDoneClose(R.string.btn_okay, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // add key ids to params Bundle for new request + Intent resultData = extras.getParcelable(EXTRA_DATA); + resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, + mSelectFragment.getSelectedMasterKeyIds()); - // set text on view - TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); - textView.setText(ssb, TextView.BufferType.SPANNABLE); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); + } + }, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // cancel + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } + }); + + // set text on view + TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); + textView.setText(ssb, TextView.BufferType.SPANNABLE); + + /* Load select pub keys fragment */ + // Check that the activity is using the layout version with + // the fragment_container FrameLayout + if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { + + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } - /* Load select pub keys fragment */ - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { + // Create an instance of the fragment + mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; + // Add the fragment to the 'fragment_container' FrameLayout + getSupportFragmentManager().beginTransaction() + .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); } - - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); + break; } - } else if (ACTION_ERROR_MESSAGE.equals(action)) { - String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); + case ACTION_ERROR_MESSAGE: { + String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); - Spannable redErrorMessage = new SpannableString(errorMessage); - redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable redErrorMessage = new SpannableString(errorMessage); + redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - setContentView(R.layout.api_remote_error_message); - initToolbar(); + setContentView(R.layout.api_remote_error_message); + initToolbar(); - // Inflate a "Done" custom action bar view - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { + // Inflate a "Done" custom action bar view + setFullScreenDialogClose( + new View.OnClickListener() { - @Override - public void onClick(View v) { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); + @Override + public void onClick(View v) { + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } } - } - ); - - // set text on view - TextView textView = (TextView) findViewById(R.id.api_app_error_message_text); - textView.setText(redErrorMessage); - } else { - Log.e(Constants.TAG, "Action does not exist!"); - setResult(RESULT_CANCELED); - finish(); + ); + + // set text on view + TextView textView = (TextView) findViewById(R.id.api_app_error_message_text); + textView.setText(redErrorMessage); + break; + } + default: + Log.e(Constants.TAG, "Action does not exist!"); + setResult(RESULT_CANCELED); + finish(); + break; } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java index dd9c0d769..f0dbf0820 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java @@ -34,7 +34,7 @@ public class CertifyActionsParcel implements Parcelable { final public long mMasterKeyId; public CertifyLevel mLevel; - public ArrayList<CertifyAction> mCertifyActions = new ArrayList<CertifyAction>(); + public ArrayList<CertifyAction> mCertifyActions = new ArrayList<>(); public CertifyActionsParcel(long masterKeyId) { mMasterKeyId = masterKeyId; 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 479810203..264b45035 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -30,10 +30,11 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.DeleteOperation; import org.sufficientlysecure.keychain.operations.EditKeyOperation; +import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.util.FileHelper; @@ -91,6 +92,8 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; + public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING"; + public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING"; public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING"; @@ -161,6 +164,10 @@ public class KeychainIntentService extends IntentService implements Progressable // certify key public static final String CERTIFY_PARCEL = "certify_parcel"; + // promote key + public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id"; + public static final String PROMOTE_TYPE = "promote_type"; + // consolidate public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery"; @@ -224,301 +231,304 @@ public class KeychainIntentService extends IntentService implements Progressable String action = intent.getAction(); // executeServiceMethod action from extra bundle - if (ACTION_CERTIFY_KEYRING.equals(action)) { - - // Input - CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL); - String keyServerUri = data.getString(UPLOAD_KEY_SERVER); + switch (action) { + case ACTION_CERTIFY_KEYRING: { - // Operation - CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled); - CertifyResult result = op.certify(parcel, keyServerUri); + // Input + CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL); + String keyServerUri = data.getString(UPLOAD_KEY_SERVER); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + // Operation + CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled); + CertifyResult result = op.certify(parcel, keyServerUri); - } else if (ACTION_CONSOLIDATE.equals(action)) { + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Operation - ConsolidateResult result; - if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { - result = new ProviderHelper(this).consolidateDatabaseStep2(this); - } else { - result = new ProviderHelper(this).consolidateDatabaseStep1(this); + break; } + case ACTION_CONSOLIDATE: { + + // Operation + ConsolidateResult result; + if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { + result = new ProviderHelper(this).consolidateDatabaseStep2(this); + } else { + result = new ProviderHelper(this).consolidateDatabaseStep1(this); + } - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } else if (ACTION_DECRYPT_METADATA.equals(action)) { + break; + } + case ACTION_DECRYPT_METADATA: - try { + try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); - byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); + String passphrase = data.getString(DECRYPT_PASSPHRASE); + byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - InputData inputData = createDecryptInputData(data); + InputData inputData = createDecryptInputData(data); /* Operation */ - Bundle resultData = new Bundle(); + Bundle resultData = new Bundle(); - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - this, new ProviderHelper(this), this, inputData, null - ); - builder.setAllowSymmetricDecryption(true) - .setPassphrase(passphrase) - .setDecryptMetadataOnly(true) - .setNfcState(nfcDecryptedSessionKey); + // verifyText and decrypt returning additional resultData values for the + // verification of signatures + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, inputData, null + ); + builder.setAllowSymmetricDecryption(true) + .setPassphrase(passphrase) + .setDecryptMetadataOnly(true) + .setNfcState(nfcDecryptedSessionKey); - DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult); + } catch (Exception e) { + sendErrorToHandler(e); + } - } else if (ACTION_DECRYPT_VERIFY.equals(action)) { + break; + case ACTION_DECRYPT_VERIFY: - try { + try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); - byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); + String passphrase = data.getString(DECRYPT_PASSPHRASE); + byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - InputData inputData = createDecryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); + InputData inputData = createDecryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); /* Operation */ - Bundle resultData = new Bundle(); + Bundle resultData = new Bundle(); - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - this, new ProviderHelper(this), this, - inputData, outStream - ); - builder.setAllowSymmetricDecryption(true) - .setPassphrase(passphrase) - .setNfcState(nfcDecryptedSessionKey); + // verifyText and decrypt returning additional resultData values for the + // verification of signatures + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, + inputData, outStream + ); + builder.setAllowSymmetricDecryption(true) + .setPassphrase(passphrase) + .setNfcState(nfcDecryptedSessionKey); - DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - outStream.close(); + outStream.close(); - resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); + resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); /* Output */ - finalizeDecryptOutputStream(data, resultData, outStream); + finalizeDecryptOutputStream(data, resultData, outStream); - Log.logDebugBundle(resultData, "resultData"); + Log.logDebugBundle(resultData, "resultData"); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } - } else if (ACTION_DELETE.equals(action)) { + break; + case ACTION_DELETE: { + + // Input + long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); + boolean isSecret = data.getBoolean(DELETE_IS_SECRET); - // Input - long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); - boolean isSecret = data.getBoolean(DELETE_IS_SECRET); + // Operation + DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this); + DeleteResult result = op.execute(masterKeyIds, isSecret); - // Operation - DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this); - DeleteResult result = op.execute(masterKeyIds, isSecret); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + break; + } + case ACTION_EDIT_KEYRING: { - } else if (ACTION_EDIT_KEYRING.equals(action)) { + // Input + SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); + String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); - // Input - SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); - String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); + // Operation + EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); + EditKeyResult result = op.execute(saveParcel, passphrase); - // Operation - EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); - EditKeyResult result = op.execute(saveParcel, passphrase); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + break; + } + case ACTION_PROMOTE_KEYRING: { - } else if (ACTION_EXPORT_KEYRING.equals(action)) { + // Input + long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); - // Input - boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); - String outputFile = data.getString(EXPORT_FILENAME); - Uri outputUri = data.getParcelable(EXPORT_URI); + // Operation + PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); + PromoteKeyResult result = op.execute(keyRingId); - boolean exportAll = data.getBoolean(EXPORT_ALL); - long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Operation - ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); - ExportResult result; - if (outputFile != null) { - result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile); - } else { - result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri); + break; } + case ACTION_EXPORT_KEYRING: { - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + // Input + boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); + String outputFile = data.getString(EXPORT_FILENAME); + Uri outputUri = data.getParcelable(EXPORT_URI); - } else if (ACTION_IMPORT_KEYRING.equals(action)) { + boolean exportAll = data.getBoolean(EXPORT_ALL); + long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); - try { + // Operation + ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); + ExportResult result; + if (outputFile != null) { + result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile); + } else { + result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri); + } + + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + + break; + } + case ACTION_IMPORT_KEYRING: { // Input String keyServer = data.getString(IMPORT_KEY_SERVER); - Iterator<ParcelableKeyRing> entries; - int numEntries; - if (data.containsKey(IMPORT_KEY_LIST)) { - // get entries from intent - ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST); - entries = list.iterator(); - numEntries = list.size(); - } else { - // get entries from cached file - ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(this, "key_import.pcl"); - IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); - entries = it; - numEntries = it.getSize(); - } + ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST); + ParcelableFileCache<ParcelableKeyRing> cache = + new ParcelableFileCache<>(this, "key_import.pcl"); // Operation ImportExportOperation importExportOperation = new ImportExportOperation( this, providerHelper, this, mActionCanceled); - ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer); - - // Special: consolidate on secret key import (cannot be cancelled!) - if (result.mSecret > 0) { - // TODO move this into the import operation - providerHelper.consolidateDatabaseStep1(this); - } - - // Special: make sure new data is synced into contacts - ContactSyncAdapterService.requestSync(); + // Either list or cache must be null, no guarantees otherwise. + ImportKeyResult result = list != null + ? importExportOperation.importKeyRings(list, keyServer) + : importExportOperation.importKeyRings(cache, keyServer); // Result sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } catch (Exception e) { - sendErrorToHandler(e); - } - - } else if (ACTION_SIGN_ENCRYPT.equals(action)) { - - try { - /* Input */ - int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); - Bundle resultData = new Bundle(); - long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); - String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); - - byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); - Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); - - String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); - - boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); - long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); - int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; - for (int i = 0; i < urisCount; i++) { - data.putInt(SELECTED_URI, i); - InputData inputData = createEncryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); - String originalFilename = getOriginalFilename(data); - - /* Operation */ - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(this), this, inputData, outStream - ); - builder.setEnableAsciiArmorOutput(useAsciiArmor) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setCompressionId(compressionId) - .setSymmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .setEncryptionMasterKeyIds(encryptionKeyIds) - .setSymmetricPassphrase(symmetricPassphrase) - .setOriginalFilename(originalFilename); + break; - try { + } + case ACTION_SIGN_ENCRYPT: - // Find the appropriate subkey to sign with - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); - long sigSubKeyId = signingRing.getSecretSignId(); - - // Set signature settings - builder.setSignatureMasterKeyId(sigMasterKeyId) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(sigKeyPassphrase) - .setSignatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .setAdditionalEncryptId(sigMasterKeyId); - if (nfcHash != null && nfcTimestamp != null) { - builder.setNfcState(nfcHash, nfcTimestamp); + try { + /* Input */ + int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); + Bundle resultData = new Bundle(); + + long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); + String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); + + byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); + Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); + + String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); + + boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); + long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); + int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); + int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; + for (int i = 0; i < urisCount; i++) { + data.putInt(SELECTED_URI, i); + InputData inputData = createEncryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); + String originalFilename = getOriginalFilename(data); + + /* Operation */ + PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( + this, new ProviderHelper(this), this, inputData, outStream + ); + builder.setEnableAsciiArmorOutput(useAsciiArmor) + .setCleartextSignature(true) + .setVersionHeader(PgpHelper.getVersionForHeader(this)) + .setCompressionId(compressionId) + .setSymmetricEncryptionAlgorithm( + Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) + .setEncryptionMasterKeyIds(encryptionKeyIds) + .setSymmetricPassphrase(symmetricPassphrase) + .setOriginalFilename(originalFilename); + + try { + + // Find the appropriate subkey to sign with + CachedPublicKeyRing signingRing = + new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); + long sigSubKeyId = signingRing.getSecretSignId(); + + // Set signature settings + builder.setSignatureMasterKeyId(sigMasterKeyId) + .setSignatureSubKeyId(sigSubKeyId) + .setSignaturePassphrase(sigKeyPassphrase) + .setSignatureHashAlgorithm( + Preferences.getPreferences(this).getDefaultHashAlgorithm()) + .setAdditionalEncryptId(sigMasterKeyId); + if (nfcHash != null && nfcTimestamp != null) { + builder.setNfcState(nfcHash, nfcTimestamp); + } + + } catch (PgpKeyNotFoundException e) { + // encrypt-only + // TODO Just silently drop the requested signature? Shouldn't we throw here? } - } catch (PgpKeyNotFoundException e) { - // encrypt-only - // TODO Just silently drop the requested signature? Shouldn't we throw here? - } - - // this assumes that the bytes are cleartext (valid for current implementation!) - if (source == IO_BYTES) { - builder.setCleartextInput(true); - } - - SignEncryptResult result = builder.build().execute(); - resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); + SignEncryptResult result = builder.build().execute(); + resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); - outStream.close(); + outStream.close(); - /* Output */ + /* Output */ + finalizeEncryptOutputStream(data, resultData, outStream); + } - finalizeEncryptOutputStream(data, resultData, outStream); + Log.logDebugBundle(resultData, "resultData"); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); } - Log.logDebugBundle(resultData, "resultData"); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - - } else if (ACTION_UPLOAD_KEYRING.equals(action)) { + break; + case ACTION_UPLOAD_KEYRING: - try { + try { /* Input */ - String keyServer = data.getString(UPLOAD_KEY_SERVER); - // and dataUri! + String keyServer = data.getString(UPLOAD_KEY_SERVER); + // and dataUri! /* Operation */ - HkpKeyserver server = new HkpKeyserver(keyServer); + HkpKeyserver server = new HkpKeyserver(keyServer); - CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); - ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); + CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); + ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); - try { - importExportOperation.uploadKeyRingToServer(server, keyring); - } catch (Keyserver.AddKeyException e) { - throw new PgpGeneralException("Unable to export key to selected server"); - } + try { + importExportOperation.uploadKeyRingToServer(server, keyring); + } catch (Keyserver.AddKeyException e) { + throw new PgpGeneralException("Unable to export key to selected server"); + } - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + } catch (Exception e) { + sendErrorToHandler(e); + } + break; } } 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 869d2e71b..142814d99 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -39,7 +39,6 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; @@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service { private BroadcastReceiver mIntentReceiver; - private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<CachedPassphrase>(); + private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<>(); Context mContext; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index a314c8768..f5df5858c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -58,7 +58,6 @@ public class SaveKeyringParcel implements Parcelable { public ArrayList<String> mRevokeUserIds; public ArrayList<Long> mRevokeSubKeys; - public ArrayList<Long> mStripSubKeys; public SaveKeyringParcel() { reset(); @@ -72,14 +71,30 @@ public class SaveKeyringParcel implements Parcelable { public void reset() { mNewUnlock = null; - mAddUserIds = new ArrayList<String>(); - mAddUserAttribute = new ArrayList<WrappedUserAttribute>(); - mAddSubKeys = new ArrayList<SubkeyAdd>(); + mAddUserIds = new ArrayList<>(); + mAddUserAttribute = new ArrayList<>(); + mAddSubKeys = new ArrayList<>(); mChangePrimaryUserId = null; - mChangeSubKeys = new ArrayList<SubkeyChange>(); - mRevokeUserIds = new ArrayList<String>(); - mRevokeSubKeys = new ArrayList<Long>(); - mStripSubKeys = new ArrayList<Long>(); + mChangeSubKeys = new ArrayList<>(); + mRevokeUserIds = new ArrayList<>(); + mRevokeSubKeys = new ArrayList<>(); + } + + /** Returns true iff this parcel does not contain any operations which require a passphrase. */ + public boolean isRestrictedOnly() { + if (mNewUnlock != null || !mAddUserIds.isEmpty() || !mAddUserAttribute.isEmpty() + || !mAddSubKeys.isEmpty() || mChangePrimaryUserId != null || !mRevokeSubKeys .isEmpty() + || !mRevokeSubKeys.isEmpty()) { + return false; + } + + for (SubkeyChange change : mChangeSubKeys) { + if (change.mRecertify || change.mFlags != null || change.mExpiry != null) { + return false; + } + } + + return true; } // performance gain for using Parcelable here would probably be negligible, @@ -112,26 +127,53 @@ public class SaveKeyringParcel implements Parcelable { } public static class SubkeyChange implements Serializable { - public long mKeyId; + public final long mKeyId; public Integer mFlags; // this is a long unix timestamp, in seconds (NOT MILLISECONDS!) public Long mExpiry; + // if this flag is true, the key will be recertified even if all above + // values are no-ops + public boolean mRecertify; + // if this flag is true, the subkey should be changed to a stripped key + public boolean mDummyStrip; + // if this is non-null, the subkey will be changed to a divert-to-card + // key for the given serial number + public byte[] mDummyDivert; public SubkeyChange(long keyId) { mKeyId = keyId; } + public SubkeyChange(long keyId, boolean recertify) { + mKeyId = keyId; + mRecertify = recertify; + } + public SubkeyChange(long keyId, Integer flags, Long expiry) { mKeyId = keyId; mFlags = flags; mExpiry = expiry; } + public SubkeyChange(long keyId, boolean dummyStrip, byte[] dummyDivert) { + this(keyId, null, null); + + // these flags are mutually exclusive! + if (dummyStrip && dummyDivert != null) { + throw new AssertionError( + "cannot set strip and divert flags at the same time - this is a bug!"); + } + mDummyStrip = dummyStrip; + mDummyDivert = dummyDivert; + } + @Override public String toString() { String out = "mKeyId: " + mKeyId + ", "; out += "mFlags: " + mFlags + ", "; - out += "mExpiry: " + mExpiry; + out += "mExpiry: " + mExpiry + ", "; + out += "mDummyStrip: " + mDummyStrip + ", "; + out += "mDummyDivert: [" + (mDummyDivert == null ? 0 : mDummyDivert.length) + " bytes]"; return out; } @@ -173,7 +215,6 @@ public class SaveKeyringParcel implements Parcelable { mRevokeUserIds = source.createStringArrayList(); mRevokeSubKeys = (ArrayList<Long>) source.readSerializable(); - mStripSubKeys = (ArrayList<Long>) source.readSerializable(); } @Override @@ -196,7 +237,6 @@ public class SaveKeyringParcel implements Parcelable { destination.writeStringList(mRevokeUserIds); destination.writeSerializable(mRevokeSubKeys); - destination.writeSerializable(mStripSubKeys); } public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() { @@ -224,8 +264,7 @@ public class SaveKeyringParcel implements Parcelable { out += "mChangeSubKeys: " + mChangeSubKeys + "\n"; out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n"; out += "mRevokeUserIds: " + mRevokeUserIds + "\n"; - out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n"; - out += "mStripSubKeys: " + mStripSubKeys; + out += "mRevokeSubKeys: " + mRevokeSubKeys; return out; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index c38d126d7..7423e6828 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -17,14 +17,21 @@ package org.sufficientlysecure.keychain.ui; +import android.app.Activity; import android.os.Bundle; +import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; import org.sufficientlysecure.keychain.R; /** - * Sets action bar + * Setups Toolbar */ public abstract class BaseActivity extends ActionBarActivity { protected Toolbar mToolbar; @@ -49,4 +56,75 @@ public abstract class BaseActivity extends ActionBarActivity { protected void setActionBarIcon(int iconRes) { mToolbar.setNavigationIcon(iconRes); } + + /** + * Inflate custom design to look like a full screen dialog, as specified in Material Design Guidelines + * see http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs + */ + protected void setFullScreenDialogDoneClose(int doneText, View.OnClickListener doneOnClickListener, + View.OnClickListener cancelOnClickListener) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate(R.layout.full_screen_dialog, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.full_screen_dialog_done_text)); + firstTextView.setText(doneText); + customActionBarView.findViewById(R.id.full_screen_dialog_done).setOnClickListener( + doneOnClickListener); + + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, + Gravity.END)); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + /** + * Close button only + */ + protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + getSupportActionBar().setDisplayShowTitleEnabled(true); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + /** + * Inflate custom design with two buttons using drawables. + * This does not conform to the Material Design Guidelines, but we deviate here as this is used + * to indicate "Allow access"/"Disallow access" to the API, which must be clearly indicated + */ + protected void setFullScreenDialogTwoButtons(int firstText, int firstDrawableId, View.OnClickListener firstOnClickListener, + int secondText, int secondDrawableId, View.OnClickListener secondOnClickListener) { + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate( + R.layout.full_screen_dialog_2, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); + firstTextView.setText(firstText); + firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( + firstOnClickListener); + TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); + secondTextView.setText(secondText); + secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( + secondOnClickListener); + + // Show the custom action bar view and hide the normal Home icon and title. + getSupportActionBar().setDisplayShowTitleEnabled(false); + getSupportActionBar().setDisplayShowHomeEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(false); + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 6850eca13..1fb88b182 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -18,9 +18,6 @@ package org.sufficientlysecure.keychain.ui; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; - import org.sufficientlysecure.keychain.R; /** 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 841485c7c..50d5e3229 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -234,7 +234,7 @@ public class CertifyKeyFragment extends LoaderFragment long lastMasterKeyId = 0; String lastName = ""; - ArrayList<String> uids = new ArrayList<String>(); + ArrayList<String> uids = new ArrayList<>(); boolean header = true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 82d3279f4..62c38d136 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.R; 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 2804a5ce6..377a9d1f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -44,7 +44,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.util.Log; public class CreateKeyFinalFragment extends Fragment { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java index 6079062a7..8aa9fa6db 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java @@ -89,7 +89,7 @@ public class CreateKeyInputFragment extends Fragment { mEmailEdit.setThreshold(1); // Start working from first character mEmailEdit.setAdapter( - new ArrayAdapter<String> + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(getActivity()) ) @@ -124,7 +124,7 @@ public class CreateKeyInputFragment extends Fragment { mNameEdit.setThreshold(1); // Start working from first character mNameEdit.setAdapter( - new ArrayAdapter<String> + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(getActivity()) ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index a84461a92..21377bcd2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -34,13 +34,13 @@ import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; import java.util.regex.Matcher; -public class DecryptActivity extends DrawerActivity { +public class DecryptActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); View actionFile = findViewById(R.id.decrypt_files); View actionFromClipboard = findViewById(R.id.decrypt_from_clipboard); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java index 59159929c..7e91889b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; 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 285078dbf..2afc4b7b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; 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 fa7abf0f5..78333a8d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -41,6 +41,8 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ShareHelper; +import java.io.UnsupportedEncodingException; + public class DecryptTextFragment extends DecryptFragment { public static final String ARG_CIPHERTEXT = "ciphertext"; @@ -111,7 +113,7 @@ public class DecryptTextFragment extends DecryptFragment { Intent prototype = createSendIntent(text); String title = getString(R.string.title_share_file); - // we don't want to decrypt the decypted, no inception ;) + // we don't want to decrypt the decrypted, no inception ;) String[] blacklist = new String[]{ Constants.PACKAGE_NAME + ".ui.DecryptTextActivity", "org.thialfihar.android.apg.ui.DecryptActivity" @@ -194,7 +196,18 @@ public class DecryptTextFragment extends DecryptFragment { byte[] decryptedMessage = returnData .getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES); - mText.setText(new String(decryptedMessage)); + String displayMessage; + if (pgpResult.getCharset() != null) { + try { + displayMessage = new String(decryptedMessage, pgpResult.getCharset()); + } catch (UnsupportedEncodingException e) { + // if we can't decode properly, just fall back to utf-8 + displayMessage = new String(decryptedMessage); + } + } else { + displayMessage = new String(decryptedMessage); + } + mText.setText(displayMessage); pgpResult.createNotify(getActivity()).show(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 492c81758..6dc2994cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; 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 afe6afb3c..25ca6e8fd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -29,7 +29,6 @@ import android.os.Messenger; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -55,6 +54,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; @@ -65,7 +65,6 @@ 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.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -147,10 +146,8 @@ public class EditKeyFragment extends LoaderFragment implements @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(((ActionBarActivity) getActivity()).getSupportActionBar(), - R.string.btn_save, R.drawable.ic_action_save, + ((EditKeyActivity) getActivity()).setFullScreenDialogDoneClose( + R.string.btn_save, new OnClickListener() { @Override public void onClick(View v) { @@ -161,16 +158,13 @@ public class EditKeyFragment extends LoaderFragment implements saveInDatabase(mCurrentPassphrase); } } - }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel, - new OnClickListener() { + }, new OnClickListener() { @Override public void onClick(View v) { - // cancel getActivity().setResult(Activity.RESULT_CANCELED); getActivity().finish(); } - } - ); + }); Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); SaveKeyringParcel saveKeyringParcel = getArguments().getParcelable(ARG_SAVE_KEYRING_PARCEL); @@ -230,10 +224,7 @@ public class EditKeyFragment extends LoaderFragment implements mSaveKeyringParcel = new SaveKeyringParcel(masterKeyId, keyRing.getFingerprint()); mPrimaryUserId = keyRing.getPrimaryUserIdWithFallback(); - } catch (PgpKeyNotFoundException e) { - finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND); - return; - } catch (NotFoundException e) { + } catch (PgpKeyNotFoundException | NotFoundException e) { finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND); return; } @@ -395,8 +386,8 @@ public class EditKeyFragment extends LoaderFragment implements // cache new returned passphrase! mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( - data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), - null + data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), + null ); } } @@ -478,12 +469,13 @@ public class EditKeyFragment extends LoaderFragment implements } break; case EditSubkeyDialogFragment.MESSAGE_STRIP: - // toggle - if (mSaveKeyringParcel.mStripSubKeys.contains(keyId)) { - mSaveKeyringParcel.mStripSubKeys.remove(keyId); - } else { - mSaveKeyringParcel.mStripSubKeys.add(keyId); + SubkeyChange change = mSaveKeyringParcel.getSubkeyChange(keyId); + if (change == null) { + mSaveKeyringParcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, null)); + break; } + // toggle + change.mDummyStrip = !change.mDummyStrip; break; } getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad(); 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 b9058a37d..611078f95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -14,7 +14,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import java.util.Date; -public abstract class EncryptActivity extends DrawerActivity { +public abstract class EncryptActivity extends BaseActivity { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_NFC = 0x00008002; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 2d1b66daa..c5404094a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -28,7 +28,6 @@ import com.tokenautocomplete.TokenCompleteTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -164,8 +163,8 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi private void updateEncryptionKeys() { List<Object> objects = mEncryptKeyView.getObjects(); - List<Long> keyIds = new ArrayList<Long>(); - List<String> userIds = new ArrayList<String>(); + List<Long> keyIds = new ArrayList<>(); + List<String> userIds = new ArrayList<>(); for (Object object : objects) { if (object instanceof EncryptKeyCompletionView.EncryptionKey) { keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId()); 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 1494d05e1..63708ae8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -122,13 +122,13 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi @Override public ArrayList<Uri> getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList<Uri>(); + if (mInputUris == null) mInputUris = new ArrayList<>(); return mInputUris; } @Override public ArrayList<Uri> getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList<Uri>(); + if (mOutputUris == null) mOutputUris = new ArrayList<>(); return mOutputUris; } @@ -252,7 +252,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi sendIntent.setType("application/octet-stream"); if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set<String> users = new HashSet<String>(); + Set<String> users = new HashSet<>(); for (String user : mEncryptionUserIds) { String[] userId = KeyRing.splitUserId(user); if (userId[1] != null) { @@ -312,10 +312,10 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_DATA.equals(getIntent().getAction())) { // lock drawer - deactivateDrawerNavigation(); +// deactivateDrawerNavigation(); // TODO: back button to key? } else { - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } // Handle intent actions @@ -382,7 +382,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi String action = intent.getAction(); Bundle extras = intent.getExtras(); String type = intent.getType(); - ArrayList<Uri> uris = new ArrayList<Uri>(); + ArrayList<Uri> uris = new ArrayList<>(); if (extras == null) { extras = new Bundle(); 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 6961f5ee7..be305cc58 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -59,7 +59,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt private View mShareFile; private ListView mSelectedFiles; private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); - private final Map<Uri, Bitmap> thumbnailCache = new HashMap<Uri, Bitmap>(); + private final Map<Uri, Bitmap> thumbnailCache = new HashMap<>(); @Override public void onAttach(Activity activity) { @@ -224,7 +224,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt @Override public void onNotifyUpdate() { // Clear cache if needed - for (Uri uri : new HashSet<Uri>(thumbnailCache.keySet())) { + for (Uri uri : new HashSet<>(thumbnailCache.keySet())) { if (!mEncryptInterface.getInputUris().contains(uri)) { thumbnailCache.remove(uri); } 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 757d1fb02..b4c12996e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -121,13 +121,13 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv @Override public ArrayList<Uri> getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList<Uri>(); + if (mInputUris == null) mInputUris = new ArrayList<>(); return mInputUris; } @Override public ArrayList<Uri> getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList<Uri>(); + if (mOutputUris == null) mOutputUris = new ArrayList<>(); return mOutputUris; } @@ -240,13 +240,14 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv sendIntent.putExtra(Intent.EXTRA_TEXT, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES))); if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set<String> users = new HashSet<String>(); + Set<String> users = new HashSet<>(); for (String user : mEncryptionUserIds) { String[] userId = KeyRing.splitUserId(user); if (userId[1] != null) { users.add(userId[1]); } } + // pass trough email addresses as extra for email applications sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); } return sendIntent; @@ -291,10 +292,10 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_TEXT.equals(getIntent().getAction())) { // lock drawer - deactivateDrawerNavigation(); +// deactivateDrawerNavigation(); // TODO: back button to key? } else { - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } // Handle intent actions diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index e487c8947..ce2a049f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.KeyEvent; import android.view.View; import android.view.Window; 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 f1677cb67..6638c9944 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -29,7 +29,6 @@ import android.os.Message; import android.os.Messenger; import android.os.Parcelable; import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.View.OnClickListener; @@ -116,105 +115,123 @@ public class ImportKeysActivity extends BaseActivity { extras = new Bundle(); } + if (action == null) { + startCloudFragment(savedInstanceState, null, false); + startListFragment(savedInstanceState, null, null, null); + return; + } + if (Intent.ACTION_VIEW.equals(action)) { // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) // delegate action to ACTION_IMPORT_KEY action = ACTION_IMPORT_KEY; } - if (ACTION_IMPORT_KEY.equals(action)) { - /* Keychain's own Actions */ - startFileFragment(savedInstanceState); + switch (action) { + case ACTION_IMPORT_KEY: { + /* Keychain's own Actions */ + startFileFragment(savedInstanceState); - if (dataUri != null) { - // action: directly load data - startListFragment(savedInstanceState, null, dataUri, null); - } else if (extras.containsKey(EXTRA_KEY_BYTES)) { - byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); + if (dataUri != null) { + // action: directly load data + startListFragment(savedInstanceState, null, dataUri, null); + } else if (extras.containsKey(EXTRA_KEY_BYTES)) { + byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); - // action: directly load data - startListFragment(savedInstanceState, importData, null, null); + // action: directly load data + startListFragment(savedInstanceState, importData, null, null); + } + break; } - } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action) - || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(action) - || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(action)) { + case ACTION_IMPORT_KEY_FROM_KEYSERVER: + case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE: + case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: { - // only used for OpenPgpService - if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { - mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); - } - if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { - /* simple search based on query or key id */ - - String query = null; - if (extras.containsKey(EXTRA_QUERY)) { - query = extras.getString(EXTRA_QUERY); - } else if (extras.containsKey(EXTRA_KEY_ID)) { - long keyId = extras.getLong(EXTRA_KEY_ID, 0); - if (keyId != 0) { - query = KeyFormattingUtils.convertKeyIdToHex(keyId); - } + // only used for OpenPgpService + if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { + mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); } + if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { + /* simple search based on query or key id */ + + String query = null; + if (extras.containsKey(EXTRA_QUERY)) { + query = extras.getString(EXTRA_QUERY); + } else if (extras.containsKey(EXTRA_KEY_ID)) { + long keyId = extras.getLong(EXTRA_KEY_ID, 0); + if (keyId != 0) { + query = KeyFormattingUtils.convertKeyIdToHex(keyId); + } + } - if (query != null && query.length() > 0) { - // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, false); + if (query != null && query.length() > 0) { + // display keyserver fragment with query + startCloudFragment(savedInstanceState, query, false); - // action: search immediately - startListFragment(savedInstanceState, null, null, query); - } else { - Log.e(Constants.TAG, "Query is empty!"); - return; - } - } else if (extras.containsKey(EXTRA_FINGERPRINT)) { - /* - * search based on fingerprint, here we can enforce a check in the end - * if the right key has been downloaded - */ + // action: search immediately + startListFragment(savedInstanceState, null, null, query); + } else { + Log.e(Constants.TAG, "Query is empty!"); + return; + } + } else if (extras.containsKey(EXTRA_FINGERPRINT)) { + /* + * search based on fingerprint, here we can enforce a check in the end + * if the right key has been downloaded + */ - String fingerprint = extras.getString(EXTRA_FINGERPRINT); - if (isFingerprintValid(fingerprint)) { - String query = "0x" + fingerprint; + String fingerprint = extras.getString(EXTRA_FINGERPRINT); + if (isFingerprintValid(fingerprint)) { + String query = "0x" + fingerprint; - // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, true); + // display keyserver fragment with query + startCloudFragment(savedInstanceState, query, true); - // action: search immediately - startListFragment(savedInstanceState, null, null, query); + // action: search immediately + startListFragment(savedInstanceState, null, null, query); + } + } else { + Log.e(Constants.TAG, + "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " + + "'fingerprint' extra!" + ); + return; } - } else { - Log.e(Constants.TAG, - "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " + - "'fingerprint' extra!" - ); - return; + break; } - } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); + case ACTION_IMPORT_KEY_FROM_FILE: { + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - // TODO!!!!! + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + } + case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: { + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else { - startCloudFragment(savedInstanceState, null, false); - startListFragment(savedInstanceState, null, null, null); + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + } + case ACTION_IMPORT_KEY_FROM_NFC: { + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); + // TODO!!!!! + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + } + default: { + startCloudFragment(savedInstanceState, null, false); + startListFragment(savedInstanceState, null, null, null); + break; + } } } - private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else @@ -356,7 +373,7 @@ public class ImportKeysActivity extends BaseActivity { // We parcel this iteratively into a file - anything we can // display here, we should be able to import. ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(this, "key_import.pcl"); + new ParcelableFileCache<>(this, "key_import.pcl"); cache.writeCache(selectedEntries); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -388,7 +405,7 @@ public class ImportKeysActivity extends BaseActivity { data.putString(KeychainIntentService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver); // get selected key entries - ArrayList<ParcelableKeyRing> keys = new ArrayList<ParcelableKeyRing>(); + ArrayList<ParcelableKeyRing> keys = new ArrayList<>(); { // change the format into ParcelableKeyRing ArrayList<ImportKeysListEntry> entries = mListFragment.getSelectedEntries(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 89826b8e9..1d12f49f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -81,7 +81,7 @@ public class ImportKeysCloudFragment extends Fragment { namesAndEmails.addAll(ContactHelper.getContactMails(getActivity())); mQueryEditText.setThreshold(3); mQueryEditText.setAdapter( - new ArrayAdapter<String> + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, namesAndEmails ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 4fe53fb09..6a6140892 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -113,7 +113,7 @@ public class ImportKeysListFragment extends ListFragment implements return mAdapter.getSelectedEntries(); } else { Log.e(Constants.TAG, "Adapter not initialized, returning empty list"); - return new ArrayList<ImportKeysListEntry>(); + return new ArrayList<>(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 1d9a9cf64..b7f3588eb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -41,15 +41,19 @@ import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; -public class KeyListActivity extends DrawerActivity { +import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; + +public class KeyListActivity extends NavDrawerActivity { public static final int REQUEST_CODE_RESULT_TO_LIST = 1; ExportHelper mExportHelper; @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +// public void onCreate(Bundle savedInstanceState) { + public void init(Bundle savedInstanceState) { + super.init(savedInstanceState); +// super.onCreate(savedInstanceState); // setActionBarIcon(R.drawable.ic_ab_drawer); setTitle(R.string.nav_keys); @@ -72,13 +76,13 @@ public class KeyListActivity extends DrawerActivity { } // now setup navigation drawer in DrawerActivity... - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } - @Override - protected void initLayout() { - setContentView(R.layout.key_list_activity); - } +// @Override +// protected void initLayout() { +// setContentView(R.layout.key_list_activity); +// } @Override public boolean onCreateOptionsMenu(Menu menu) { 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 7fa403485..4e5e8c631 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -31,7 +31,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -52,7 +51,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; @@ -60,16 +58,14 @@ import android.widget.TextView; 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.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.util.KeyUpdateHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -78,15 +74,12 @@ import org.sufficientlysecure.keychain.ui.widget.ListAwareSwipeRefreshLayout; import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import edu.cmu.cylab.starslinger.exchange.ExchangeActivity; -import edu.cmu.cylab.starslinger.exchange.ExchangeConfig; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; @@ -98,6 +91,8 @@ public class KeyListFragment extends LoaderFragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> { + ExportHelper mExportHelper; + private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; private ListAwareSwipeRefreshLayout mSwipeRefreshLayout; @@ -110,6 +105,14 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private SearchView mSearchView; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mExportHelper = new ExportHelper(getActivity()); + + } + /** * Load custom layout with StickyListView from library */ @@ -453,6 +456,15 @@ public class KeyListFragment extends LoaderFragment @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + inflater.inflate(R.menu.key_list, menu); + + if (Constants.DEBUG) { + menu.findItem(R.id.menu_key_list_debug_cons).setVisible(true); + menu.findItem(R.id.menu_key_list_debug_read).setVisible(true); + menu.findItem(R.id.menu_key_list_debug_write).setVisible(true); + menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true); + } + // Get the searchview MenuItem searchItem = menu.findItem(R.id.menu_key_list_search); @@ -489,6 +501,71 @@ public class KeyListFragment extends LoaderFragment } @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_key_list_add: + Intent scanQrCode = new Intent(getActivity(), QrCodeScanActivity.class); + scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); + startActivityForResult(scanQrCode, 0); + return true; + + case R.id.menu_key_list_search_cloud: + searchCloud(); + return true; + + case R.id.menu_key_list_create: + createKey(); + return true; + + case R.id.menu_key_list_import_existing_key: + Intent intentImportExisting = new Intent(getActivity(), ImportKeysActivity.class); + intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); + startActivityForResult(intentImportExisting, 0); + return true; + + case R.id.menu_key_list_export: + mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true); + return true; + + case R.id.menu_key_list_debug_cons: + consolidate(); + return true; + + case R.id.menu_key_list_debug_read: + try { + KeychainDatabase.debugBackup(getActivity(), true); + Notify.showNotify(getActivity(), "Restored debug_backup.db", Notify.Style.INFO); + 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); + } + 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); + } catch (IOException e) { + Log.e(Constants.TAG, "IO Error", e); + Notify.showNotify(getActivity(), "IO Error: " + e.getMessage(), Notify.Style.ERROR); + } + return true; + + case R.id.menu_key_list_debug_first_time: + Preferences prefs = Preferences.getPreferences(getActivity()); + prefs.setFirstTime(true); + Intent intent = new Intent(getActivity(), FirstTimeActivity.class); + startActivity(intent); + getActivity().finish(); + return true; + + default: + return super.onOptionsItemSelected(item); + } + } + + @Override public boolean onQueryTextSubmit(String s) { return true; } @@ -510,6 +587,77 @@ public class KeyListFragment extends LoaderFragment return true; } + + private void searchCloud() { + Intent importIntent = new Intent(getActivity(), ImportKeysActivity.class); + importIntent.putExtra(ImportKeysActivity.EXTRA_QUERY, (String) null); // hack to show only cloud tab + startActivity(importIntent); + } + + private void createKey() { + Intent intent = new Intent(getActivity(), CreateKeyActivity.class); + startActivityForResult(intent, 0); + } + + private void consolidate() { + // Message is received after importing is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( + getActivity(), + getString(R.string.progress_importing), + ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + if (returnData == null) { + return; + } + final ConsolidateResult result = + returnData.getParcelable(OperationResult.EXTRA_RESULT); + if (result == null) { + return; + } + + result.createNotify(getActivity()).show(); + } + } + }; + + // Send all information needed to service to import key in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + intent.setAction(KeychainIntentService.ACTION_CONSOLIDATE); + + // fill values for this action + Bundle data = new Bundle(); + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + saveHandler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + /** * Implements StickyListHeadersAdapter from library */ @@ -517,7 +665,7 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private LayoutInflater mInflater; - private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); + private HashMap<Integer, Boolean> mSelection = new HashMap<>(); public KeyListAdapter(Context context, Cursor c, int flags) { super(context, c, flags); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index fd74e1654..0de7bb391 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -19,11 +19,9 @@ package org.sufficientlysecure.keychain.ui; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; public class LogDisplayActivity extends BaseActivity { @@ -32,8 +30,7 @@ public class LogDisplayActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java new file mode 100644 index 000000000..5381b1ab3 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; +import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; + +import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; + +public abstract class NavDrawerActivity extends MaterialNavigationDrawer { + + @Override + public void init(Bundle savedInstanceState) { + // don't open drawer on first run + disableLearningPattern(); + +// addMultiPaneSupport(); + + // set the header image + // create and set the header + View view = LayoutInflater.from(this).inflate(R.layout.custom_drawer, null); + setDrawerHeaderCustom(view); + + // create sections + addSection(newSection(getString(R.string.title_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + + addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); + addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); + addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class))); + addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); + + // create bottom section + addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index 3a70502ea..7311f4879 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -15,7 +15,6 @@ import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.WindowManager; import android.widget.Toast; @@ -23,13 +22,11 @@ import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Locale; /** * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant @@ -91,33 +88,38 @@ public class NfcActivity extends BaseActivity { mKeyId = data.getLong(EXTRA_KEY_ID); } - if (ACTION_SIGN_HASH.equals(action)) { - mAction = action; - mPin = data.getString(EXTRA_PIN); - mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); - mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - } else if (ACTION_DECRYPT_SESSION_KEY.equals(action)) { - mAction = action; - mPin = data.getString(EXTRA_PIN); - mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - } else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { - Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); - toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); - finish(); - } else { - Log.d(Constants.TAG, "Action not supported: " + action); + switch (action) { + case ACTION_SIGN_HASH: + mAction = action; + mPin = data.getString(EXTRA_PIN); + mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); + mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); + mServiceIntent = data.getParcelable(EXTRA_DATA); + + Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); + Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); + Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + break; + case ACTION_DECRYPT_SESSION_KEY: + mAction = action; + mPin = data.getString(EXTRA_PIN); + mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); + mServiceIntent = data.getParcelable(EXTRA_DATA); + + Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); + Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); + Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + break; + case NfcAdapter.ACTION_TAG_DISCOVERED: + Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); + toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); + finish(); + break; + default: + Log.d(Constants.TAG, "Action not supported: " + action); + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index 945d98379..3e8d688fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -15,7 +15,6 @@ import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.WindowManager; import android.widget.Toast; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java index 93778fd0c..872e888a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java @@ -209,9 +209,7 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); } - } catch (IOException e) { - e.printStackTrace(); - } catch (FormatException e) { + } catch (IOException | FormatException e) { e.printStackTrace(); } @@ -236,9 +234,7 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa nfc.setText(R.string.nfc_wrong_tag); } } - } catch (IOException e) { - e.printStackTrace(); - } catch (FormatException e) { + } catch (IOException | FormatException e) { e.printStackTrace(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java index 28488879b..1a7a028c6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java @@ -203,7 +203,7 @@ public class QrCodeScanActivity extends FragmentActivity { data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); - ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<ParcelableKeyRing>(); + ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>(); selectedEntries.add(keyEntry); data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); 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 42ad2258a..ef1d797be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -20,14 +20,12 @@ package org.sufficientlysecure.keychain.ui; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -45,8 +43,7 @@ public class QrCodeViewActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { 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 d5193b2a2..f95644aff 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -27,13 +27,9 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.FragmentActivity; -import android.support.v7.app.ActionBarActivity; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.NumberPicker; -import android.widget.Spinner; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -50,7 +46,6 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache; import java.io.IOException; import java.util.ArrayList; -import java.util.List; import edu.cmu.cylab.starslinger.exchange.ExchangeActivity; import edu.cmu.cylab.starslinger.exchange.ExchangeConfig; @@ -192,7 +187,7 @@ public class SafeSlingerActivity extends BaseActivity { // We parcel this iteratively into a file - anything we can // display here, we should be able to import. ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(activity, "key_import.pcl"); + new ParcelableFileCache<>(activity, "key_import.pcl"); cache.writeCache(it.size(), it.iterator()); // fill values for this action @@ -220,7 +215,7 @@ public class SafeSlingerActivity extends BaseActivity { } private static ArrayList<ParcelableKeyRing> getSlingedKeys(Bundle extras) { - ArrayList<ParcelableKeyRing> list = new ArrayList<ParcelableKeyRing>(); + ArrayList<ParcelableKeyRing> list = new ArrayList<>(); if (extras != null) { byte[] d; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index f7e19706e..0e3374833 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -20,12 +20,10 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; public class SelectPublicKeyActivity extends BaseActivity { @@ -47,21 +45,19 @@ public class SelectPublicKeyActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.btn_okay, new View.OnClickListener() { @Override public void onClick(View v) { - // ok okClicked(); } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + }, + new View.OnClickListener() { @Override public void onClick(View v) { - // cancel cancelClicked(); } - } - ); + }); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index af583bf89..afec3bf06 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -42,7 +42,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; @@ -216,7 +215,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T public long[] getSelectedMasterKeyIds() { // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key // ids! - Vector<Long> vector = new Vector<Long>(); + Vector<Long> vector = new Vector<>(); for (int i = 0; i < getListView().getCount(); ++i) { if (getListView().isItemChecked(i)) { vector.add(mAdapter.getMasterKeyId(i)); @@ -238,7 +237,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T * @return */ public String[] getSelectedUserIds() { - Vector<String> userIds = new Vector<String>(); + Vector<String> userIds = new Vector<>(); for (int i = 0; i < getListView().getCount(); ++i) { if (getListView().isItemChecked(i)) { userIds.add(mAdapter.getUserId(i)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 365e8026c..080dc2495 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -28,7 +27,6 @@ import android.view.ViewGroup; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.widget.Editor; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; @@ -52,21 +50,19 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.btn_save, new View.OnClickListener() { @Override public void onClick(View v) { - // ok okClicked(); } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + }, + new View.OnClickListener() { @Override public void onClick(View v) { - // cancel cancelClicked(); } - } - ); + }); mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -140,7 +136,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi } private Vector<String> serverList() { - Vector<String> servers = new Vector<String>(); + Vector<String> servers = new Vector<>(); for (int i = 0; i < mEditors.getChildCount(); ++i) { KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); String tmp = editor.getValue(); @@ -153,7 +149,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi private void okClicked() { Intent data = new Intent(); - Vector<String> servers = new Vector<String>(); + Vector<String> servers = new Vector<>(); for (int i = 0; i < mEditors.getChildCount(); ++i) { KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); String tmp = editor.getValue(); 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 6cf346c97..ed86fea0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -24,7 +24,6 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBarActivity; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; @@ -57,7 +56,7 @@ public class UploadKeyActivity extends BaseActivity { mUploadButton = findViewById(R.id.upload_key_action_upload); mKeyServerSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) .getKeyServers() ); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index a88b0f7cf..05d9dd58e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -27,9 +27,6 @@ import android.support.v4.app.NavUtils; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; import android.text.format.DateFormat; import android.view.MenuItem; import android.view.View; @@ -37,7 +34,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.pgp.WrappedSignature; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java index 7176232c5..471f55c47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java @@ -20,14 +20,11 @@ package org.sufficientlysecure.keychain.ui; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; @@ -44,8 +41,7 @@ public class ViewKeyAdvancedActivity extends BaseActivity { mProviderHelper = new ProviderHelper(this); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index aa260b654..7c47cbd0d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -228,10 +228,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements } startActivity(Intent.createChooser(sendIntent, title)); } - } catch (PgpGeneralException e) { - Log.e(Constants.TAG, "error processing key!", e); - Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); - } catch (IOException e) { + } catch (PgpGeneralException | IOException e) { Log.e(Constants.TAG, "error processing key!", e); Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); } catch (ProviderHelper.NotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 6c81e9193..8e82dd7d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -95,8 +95,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { * @see org.sufficientlysecure.keychain.operations.ImportExportOperation */ public ArrayList<ImportKeysListEntry> getSelectedEntries() { - ArrayList<ImportKeysListEntry> result = new ArrayList<ImportKeysListEntry>(); - ArrayList<ImportKeysListEntry> secrets = new ArrayList<ImportKeysListEntry>(); + ArrayList<ImportKeysListEntry> result = new ArrayList<>(); + ArrayList<ImportKeysListEntry> secrets = new ArrayList<>(); if (mData == null) { return result; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index 176c3ff5b..235fdf1d5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -39,7 +39,7 @@ public class ImportKeysListCloudLoader Preferences.CloudSearchPrefs mCloudPrefs; String mServerQuery; - private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>(); + private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<>(); private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { @@ -51,7 +51,7 @@ public class ImportKeysListCloudLoader @Override public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, null); if (mServerQuery == null) { Log.e(Constants.TAG, "mServerQuery is null!"); @@ -119,7 +119,7 @@ public class ImportKeysListCloudLoader mEntryList.addAll(searchResult); } GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_OK, null); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, getKeyResult); } catch (Keyserver.CloudSearchFailureException e) { // convert exception to result parcel int error = GetKeyResult.RESULT_ERROR; @@ -140,7 +140,7 @@ public class ImportKeysListCloudLoader OperationResult.OperationLog log = new OperationResult.OperationLog(); log.add(logType, 0); GetKeyResult getKeyResult = new GetKeyResult(error, log); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, getKeyResult); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index cecad2716..144a16a48 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -35,28 +35,15 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { - public static class NonPgpPartException extends Exception { - private int mCount; - - public NonPgpPartException(int count) { - this.mCount = count; - } - - public int getCount() { - return mCount; - } - } - final Context mContext; final InputData mInputData; - ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>(); - LongSparseArray<ParcelableKeyRing> mParcelableRings = new LongSparseArray<ParcelableKeyRing>(); + ArrayList<ImportKeysListEntry> mData = new ArrayList<>(); + LongSparseArray<ParcelableKeyRing> mParcelableRings = new LongSparseArray<>(); AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; public ImportKeysListLoader(Context context, InputData inputData) { @@ -73,7 +60,7 @@ public class ImportKeysListLoader } GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_OK, null); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mData, getKeyResult); if (mInputData == null) { Log.e(Constants.TAG, "Input data is null!"); @@ -140,7 +127,7 @@ public class ImportKeysListLoader OperationResult.OperationLog log = new OperationResult.OperationLog(); log.add(OperationResult.LogType.MSG_GET_NO_VALID_KEYS, 0); GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_ERROR_NO_VALID_KEYS, log); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> + mEntryListWrapper = new AsyncTaskResultWrapper<> (mData, getKeyResult); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java index 80d605fb9..b8fe21941 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java @@ -33,7 +33,7 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues( Map<K, V> map) { - SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>( + SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<>( new Comparator<Map.Entry<K, V>>() { @Override public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java index 9f29826ef..47ad5e664 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java @@ -44,7 +44,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { public MultiUserIdsAdapter(Context context, Cursor c, int flags) { super(context, c, flags); mInflater = LayoutInflater.from(context); - mCheckStates = new ArrayList<Boolean>(); + mCheckStates = new ArrayList<>(); } @Override @@ -148,7 +148,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { } public ArrayList<CertifyAction> getSelectedCertifyActions() { - LongSparseArray<CertifyAction> actions = new LongSparseArray<CertifyAction>(); + LongSparseArray<CertifyAction> actions = new LongSparseArray<>(); for (int i = 0; i < mCheckStates.size(); i++) { if (mCheckStates.get(i)) { mCursor.moveToPosition(i); @@ -171,7 +171,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { } } - ArrayList<CertifyAction> result = new ArrayList<CertifyAction>(actions.size()); + ArrayList<CertifyAction> result = new ArrayList<>(actions.size()); for (int i = 0; i < actions.size(); i++) { result.add(actions.valueAt(i)); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java index 330254a8f..963e77fe9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java @@ -27,7 +27,7 @@ import java.util.ArrayList; public class PagerTabStripAdapter extends FragmentPagerAdapter { protected final Activity mActivity; - protected final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); + protected final ArrayList<TabInfo> mTabs = new ArrayList<>(); static final class TabInfo { public final Class<?> clss; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index a032e96fc..5ba09be7e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -35,7 +35,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; @@ -160,7 +160,11 @@ public class SubkeysAdapter extends CursorAdapter { cursor.getString(INDEX_KEY_CURVE_OID) )); - if (mSaveKeyringParcel != null && mSaveKeyringParcel.mStripSubKeys.contains(keyId)) { + SubkeyChange change = mSaveKeyringParcel != null + ? mSaveKeyringParcel.getSubkeyChange(keyId) + : null; + + if (change != null && change.mDummyStrip) { algorithmStr.append(", "); final SpannableString boldStripped = new SpannableString( context.getString(R.string.key_stripped) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java index 9ddfa90be..44afed351 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java @@ -33,7 +33,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. private final Context mContext; private final ActionBar mActionBar; private final ViewPager mViewPager; - private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); + private final ArrayList<TabInfo> mTabs = new ArrayList<>(); static final class TabInfo { public final Class<?> clss; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index a778c7fa7..52c21e253 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -221,7 +221,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC } public ArrayList<String> getSelectedUserIds() { - ArrayList<String> result = new ArrayList<String>(); + ArrayList<String> result = new ArrayList<>(); for (int i = 0; i < mCheckStates.size(); i++) { if (mCheckStates.get(i)) { mCursor.moveToPosition(i); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java index b4119a5eb..d5376cbdc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java @@ -145,20 +145,20 @@ public class AddSubkeyDialogFragment extends DialogFragment { } { - ArrayList<Choice<Algorithm>> choices = new ArrayList<Choice<Algorithm>>(); - choices.add(new Choice<Algorithm>(Algorithm.DSA, getResources().getString( + ArrayList<Choice<Algorithm>> choices = new ArrayList<>(); + choices.add(new Choice<>(Algorithm.DSA, getResources().getString( R.string.dsa))); if (!mWillBeMasterKey) { - choices.add(new Choice<Algorithm>(Algorithm.ELGAMAL, getResources().getString( + choices.add(new Choice<>(Algorithm.ELGAMAL, getResources().getString( R.string.elgamal))); } - choices.add(new Choice<Algorithm>(Algorithm.RSA, getResources().getString( + choices.add(new Choice<>(Algorithm.RSA, getResources().getString( R.string.rsa))); - choices.add(new Choice<Algorithm>(Algorithm.ECDSA, getResources().getString( + choices.add(new Choice<>(Algorithm.ECDSA, getResources().getString( R.string.ecdsa))); - choices.add(new Choice<Algorithm>(Algorithm.ECDH, getResources().getString( + choices.add(new Choice<>(Algorithm.ECDH, getResources().getString( R.string.ecdh))); - ArrayAdapter<Choice<Algorithm>> adapter = new ArrayAdapter<Choice<Algorithm>>(context, + ArrayAdapter<Choice<Algorithm>> adapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, choices); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mAlgorithmSpinner.setAdapter(adapter); @@ -172,20 +172,20 @@ public class AddSubkeyDialogFragment extends DialogFragment { } // dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change - ArrayAdapter<CharSequence> keySizeAdapter = new ArrayAdapter<CharSequence>(context, android.R.layout.simple_spinner_item, + ArrayAdapter<CharSequence> keySizeAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, new ArrayList<CharSequence>(Arrays.asList(getResources().getStringArray(R.array.rsa_key_size_spinner_values)))); keySizeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mKeySizeSpinner.setAdapter(keySizeAdapter); mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length { - ArrayList<Choice<Curve>> choices = new ArrayList<Choice<Curve>>(); + ArrayList<Choice<Curve>> choices = new ArrayList<>(); - choices.add(new Choice<Curve>(Curve.NIST_P256, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P256, getResources().getString( R.string.key_curve_nist_p256))); - choices.add(new Choice<Curve>(Curve.NIST_P384, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P384, getResources().getString( R.string.key_curve_nist_p384))); - choices.add(new Choice<Curve>(Curve.NIST_P521, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P521, getResources().getString( R.string.key_curve_nist_p521))); /* @see SaveKeyringParcel @@ -197,7 +197,7 @@ public class AddSubkeyDialogFragment extends DialogFragment { R.string.key_curve_bp_p512))); */ - ArrayAdapter<Choice<Curve>> adapter = new ArrayAdapter<Choice<Curve>>(context, + ArrayAdapter<Choice<Curve>> adapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, choices); mCurveSpinner.setAdapter(adapter); // make NIST P-256 the default diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java index 3eef04aa7..a4ecc7c27 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java @@ -85,7 +85,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA mMessenger = getArguments().getParcelable(ARG_MESSENGER); String predefinedName = getArguments().getString(ARG_NAME); - ArrayAdapter<String> autoCompleteEmailAdapter = new ArrayAdapter<String> + ArrayAdapter<String> autoCompleteEmailAdapter = new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(getActivity()) ); @@ -150,7 +150,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA mName.setThreshold(1); // Start working from first character mName.setAdapter( - new ArrayAdapter<String> + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(getActivity()) ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index 0926de1d0..879e3f6da 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -28,7 +28,6 @@ import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.widget.Toast; -import org.apache.http.conn.scheme.Scheme; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.FileHelper; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java deleted file mode 100644 index edd12ec73..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.util; - -import android.app.Activity; -import android.support.v7.app.ActionBar; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; - -public class ActionBarHelper { - - /** - * Sets custom view on ActionBar for Done/Cancel activities - * - * @param actionBar - * @param firstText - * @param firstDrawableId - * @param firstOnClickListener - * @param secondText - * @param secondDrawableId - * @param secondOnClickListener - */ - public static void setTwoButtonView(ActionBar actionBar, - int firstText, int firstDrawableId, OnClickListener firstOnClickListener, - int secondText, int secondDrawableId, OnClickListener secondOnClickListener) { - - // Inflate the custom action bar view - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate( - R.layout.actionbar_custom_view_done_cancel, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); - secondTextView.setText(secondText); - secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - secondOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - - /** - * Sets custom view on ActionBar for Done activities - * - * @param actionBar - * @param firstText - * @param firstOnClickListener - */ - public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId, - OnClickListener firstOnClickListener) { - // Inflate a "Done" custom action bar view to serve as the "Up" affordance. - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater - .inflate(R.layout.actionbar_custom_view_done, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java index 36f38045f..0bb4100c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java @@ -47,7 +47,7 @@ public class QrCodeUtils { */ public static Bitmap getQRCodeBitmap(final String input, final int size) { try { - final Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); + final Hashtable<EncodeHintType, Object> hints = new Hashtable<>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); final BitMatrix result = new QRCodeWriter().encode(input, BarcodeFormat.QR_CODE, size, size, hints); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 14f42eb04..904cde47e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -29,7 +29,6 @@ import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; public class CertifyKeySpinner extends KeySpinner { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index e03a14989..5f6f13181 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -28,7 +28,6 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.text.SpannableStringBuilder; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -46,7 +45,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; @@ -165,7 +163,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView { setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList())); return; } - ArrayList<EncryptionKey> keys = new ArrayList<EncryptionKey>(); + ArrayList<EncryptionKey> keys = new ArrayList<>(); while (cursor.moveToNext()) { try { EncryptionKey key = new EncryptionKey(cursor); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java index b456b61ab..34e7b639a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java @@ -33,17 +33,16 @@ import org.sufficientlysecure.keychain.R; /** * Class representing a LinearLayout that can fold and hide it's content when pressed * To use just add the following to your xml layout - - <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - custom:foldedLabel="@string/TEXT_TO_DISPLAY_WHEN_FOLDED" - custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED"> - - <include layout="@layout/ELEMENTS_TO_BE_FOLDED"/> - - </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout> - + * <p/> + * <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout + * android:layout_width="wrap_content" + * android:layout_height="wrap_content" + * custom:foldedLabel="@string/TEXT_TO_DISPLAY_WHEN_FOLDED" + * custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED"> + * <p/> + * <include layout="@layout/ELEMENTS_TO_BE_FOLDED"/> + * <p/> + * </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout> */ public class FoldableLinearLayout extends LinearLayout { @@ -75,6 +74,7 @@ public class FoldableLinearLayout extends LinearLayout { /** * Load given attributes to inner variables, + * * @param context * @param attrs */ @@ -87,8 +87,8 @@ public class FoldableLinearLayout extends LinearLayout { a.recycle(); } // If any attribute isn't found then set a default one - mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.id.none) : mFoldedLabel; - mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.id.none) : mUnFoldedLabel; + mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.string.none) : mFoldedLabel; + mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.string.none) : mUnFoldedLabel; } @Override @@ -138,7 +138,7 @@ public class FoldableLinearLayout extends LinearLayout { private void initialiseInnerViews() { mFoldableIcon = (ImageView) mFoldableLayout.findViewById(R.id.foldableIcon); - mFoldableIcon.setImageResource(R.drawable.ic_action_expand); + mFoldableIcon.setImageResource(R.drawable.ic_expand_more_black_24dp); mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText); mFoldableTextView.setText(mFoldedLabel); @@ -151,7 +151,7 @@ public class FoldableLinearLayout extends LinearLayout { public void onClick(View view) { mFolded = !mFolded; if (mFolded) { - mFoldableIcon.setImageResource(R.drawable.ic_action_collapse); + mFoldableIcon.setImageResource(R.drawable.ic_expand_less_black_24dp); mFoldableContainer.setVisibility(View.VISIBLE); AlphaAnimation animation = new AlphaAnimation(0f, 1f); animation.setDuration(mShortAnimationDuration); @@ -159,12 +159,13 @@ public class FoldableLinearLayout extends LinearLayout { mFoldableTextView.setText(mUnFoldedLabel); } else { - mFoldableIcon.setImageResource(R.drawable.ic_action_expand); + mFoldableIcon.setImageResource(R.drawable.ic_expand_more_black_24dp); AlphaAnimation animation = new AlphaAnimation(1f, 0f); animation.setDuration(mShortAnimationDuration); animation.setAnimationListener(new Animation.AnimationListener() { @Override - public void onAnimationStart(Animation animation) { } + public void onAnimationStart(Animation animation) { + } @Override public void onAnimationEnd(Animation animation) { @@ -173,7 +174,8 @@ public class FoldableLinearLayout extends LinearLayout { } @Override - public void onAnimationRepeat(Animation animation) { } + public void onAnimationRepeat(Animation animation) { + } }); mFoldableContainer.startAnimation(animation); mFoldableTextView.setText(mFoldedLabel); @@ -185,6 +187,7 @@ public class FoldableLinearLayout extends LinearLayout { /** * Adds provided child view to foldableContainer View + * * @param child */ @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java index b3c3eb417..3403208d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java @@ -20,13 +20,8 @@ package org.sufficientlysecure.keychain.ui.widget; import android.content.Context; import android.support.v4.widget.NoScrollableSwipeRefreshLayout; import android.util.AttributeSet; -import android.view.InputDevice; -import android.view.InputDevice.MotionRange; import android.view.MotionEvent; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - import se.emilsjolander.stickylistheaders.StickyListHeadersListView; public class ListAwareSwipeRefreshLayout extends NoScrollableSwipeRefreshLayout { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java index 59d05a62e..9c8e4aedb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java @@ -26,7 +26,6 @@ import android.support.v4.content.Loader; import android.util.AttributeSet; import android.widget.ImageView; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java index 99db634ac..c1955f75b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java @@ -23,7 +23,6 @@ import android.app.Activity; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import java.util.HashMap; @@ -32,9 +31,9 @@ import java.util.HashMap; public class AlgorithmNames { Activity mActivity; - HashMap<Integer, String> mEncryptionNames = new HashMap<Integer, String>(); - HashMap<Integer, String> mHashNames = new HashMap<Integer, String>(); - HashMap<Integer, String> mCompressionNames = new HashMap<Integer, String>(); + HashMap<Integer, String> mEncryptionNames = new HashMap<>(); + HashMap<Integer, String> mHashNames = new HashMap<>(); + HashMap<Integer, String> mCompressionNames = new HashMap<>(); public AlgorithmNames(Activity context) { super(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index 4ce7a1bac..11b29f521 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -73,20 +73,20 @@ public class ContactHelper { ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?"; public static final String ID_SELECTION = ContactsContract.RawContacts._ID + "=?"; - private static final Map<String, Bitmap> photoCache = new HashMap<String, Bitmap>(); + private static final Map<String, Bitmap> photoCache = new HashMap<>(); public static List<String> getPossibleUserEmails(Context context) { Set<String> accountMails = getAccountEmails(context); accountMails.addAll(getMainProfileContactEmails(context)); // now return the Set (without duplicates) as a List - return new ArrayList<String>(accountMails); + return new ArrayList<>(accountMails); } public static List<String> getPossibleUserNames(Context context) { Set<String> accountMails = getAccountEmails(context); Set<String> names = getContactNamesFromEmails(context, accountMails); names.addAll(getMainProfileContactName(context)); - return new ArrayList<String>(names); + return new ArrayList<>(names); } /** @@ -97,7 +97,7 @@ public class ContactHelper { */ private static Set<String> getAccountEmails(Context context) { final Account[] accounts = AccountManager.get(context).getAccounts(); - final Set<String> emailSet = new HashSet<String>(); + final Set<String> emailSet = new HashSet<>(); for (Account account : accounts) { if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) { emailSet.add(account.name); @@ -116,7 +116,7 @@ public class ContactHelper { */ private static Set<String> getContactNamesFromEmails(Context context, Set<String> emails) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - Set<String> names = new HashSet<String>(); + Set<String> names = new HashSet<>(); for (String email : emails) { ContentResolver resolver = context.getContentResolver(); Cursor profileCursor = resolver.query( @@ -128,7 +128,7 @@ public class ContactHelper { ); if (profileCursor == null) return null; - Set<String> currNames = new HashSet<String>(); + Set<String> currNames = new HashSet<>(); while (profileCursor.moveToNext()) { String name = profileCursor.getString(1); if (name != null) { @@ -140,7 +140,7 @@ public class ContactHelper { } return names; } else { - return new HashSet<String>(); + return new HashSet<>(); } } @@ -172,7 +172,7 @@ public class ContactHelper { ); if (profileCursor == null) return null; - Set<String> emails = new HashSet<String>(); + Set<String> emails = new HashSet<>(); while (profileCursor.moveToNext()) { String email = profileCursor.getString(0); if (email != null) { @@ -182,7 +182,7 @@ public class ContactHelper { profileCursor.close(); return emails; } else { - return new HashSet<String>(); + return new HashSet<>(); } } @@ -201,7 +201,7 @@ public class ContactHelper { null, null, null); if (profileCursor == null) return null; - Set<String> names = new HashSet<String>(); + Set<String> names = new HashSet<>(); // should only contain one entry! while (profileCursor.moveToNext()) { String name = profileCursor.getString(0); @@ -210,9 +210,9 @@ public class ContactHelper { } } profileCursor.close(); - return new ArrayList<String>(names); + return new ArrayList<>(names); } else { - return new ArrayList<String>(); + return new ArrayList<>(); } } @@ -221,9 +221,9 @@ public class ContactHelper { Cursor mailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Email.DATA}, null, null, null); - if (mailCursor == null) return new ArrayList<String>(); + if (mailCursor == null) return new ArrayList<>(); - Set<String> mails = new HashSet<String>(); + Set<String> mails = new HashSet<>(); while (mailCursor.moveToNext()) { String email = mailCursor.getString(0); if (email != null) { @@ -231,7 +231,7 @@ public class ContactHelper { } } mailCursor.close(); - return new ArrayList<String>(mails); + return new ArrayList<>(mails); } public static List<String> getContactNames(Context context) { @@ -239,9 +239,9 @@ public class ContactHelper { Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, new String[]{ContactsContract.Contacts.DISPLAY_NAME}, null, null, null); - if (cursor == null) return new ArrayList<String>(); + if (cursor == null) return new ArrayList<>(); - Set<String> names = new HashSet<String>(); + Set<String> names = new HashSet<>(); while (cursor.moveToNext()) { String name = cursor.getString(0); if (name != null) { @@ -249,7 +249,7 @@ public class ContactHelper { } } cursor.close(); - return new ArrayList<String>(names); + return new ArrayList<>(names); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @@ -309,7 +309,7 @@ public class ContactHelper { boolean isExpired = !cursor.isNull(4) && new Date(cursor.getLong(4) * 1000).before(new Date()); boolean isRevoked = cursor.getInt(5) > 0; int rawContactId = findRawContactId(resolver, fingerprint); - ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); + ArrayList<ContentProviderOperation> ops = new ArrayList<>(); // Do not store expired or revoked keys in contact db - and remove them if they already exist if (isExpired || isRevoked) { @@ -351,7 +351,7 @@ public class ContactHelper { * @return a set of all key fingerprints currently present in the contact db */ private static Set<String> getRawContactFingerprints(ContentResolver resolver) { - HashSet<String> result = new HashSet<String>(); + HashSet<String> result = new HashSet<>(); Cursor fingerprints = resolver.query(ContactsContract.RawContacts.CONTENT_URI, SOURCE_ID_PROJECTION, ACCOUNT_TYPE_SELECTION, new String[]{Constants.ACCOUNT_TYPE}, null); if (fingerprints != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java index 49d4d8bf8..8334b37ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java @@ -42,13 +42,13 @@ public class EmailKeyHelper { public static void importAll(Context context, Messenger messenger, List<String> mails) { // Collect all candidates as ImportKeysListEntry (set for deduplication) - Set<ImportKeysListEntry> entries = new HashSet<ImportKeysListEntry>(); + Set<ImportKeysListEntry> entries = new HashSet<>(); for (String mail : mails) { entries.addAll(getEmailKeys(context, mail)); } // Put them in a list and import - ArrayList<ParcelableKeyRing> keys = new ArrayList<ParcelableKeyRing>(entries.size()); + ArrayList<ParcelableKeyRing> keys = new ArrayList<>(entries.size()); for (ImportKeysListEntry entry : entries) { keys.add(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(), null)); } @@ -56,7 +56,7 @@ public class EmailKeyHelper { } public static Set<ImportKeysListEntry> getEmailKeys(Context context, String mail) { - Set<ImportKeysListEntry> keys = new HashSet<ImportKeysListEntry>(); + Set<ImportKeysListEntry> keys = new HashSet<>(); // Try _hkp._tcp SRV record first String[] mailparts = mail.split("@"); @@ -90,7 +90,7 @@ public class EmailKeyHelper { } public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) { - Set<ImportKeysListEntry> keys = new HashSet<ImportKeysListEntry>(); + Set<ImportKeysListEntry> keys = new HashSet<>(); try { for (ImportKeysListEntry key : keyServer.search(mail)) { if (key.isRevoked() || key.isExpired()) continue; @@ -103,6 +103,6 @@ public class EmailKeyHelper { } catch (Keyserver.QueryFailedException ignored) { } catch (Keyserver.QueryNeedsRepairException ignored) { } - return new ArrayList<ImportKeysListEntry>(keys); + return new ArrayList<>(keys); } } 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 7492d95b2..1d78ed80e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java @@ -24,13 +24,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; -import android.support.v7.app.ActionBarActivity; -import android.widget.Toast; +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.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; @@ -42,9 +40,9 @@ import java.io.File; public class ExportHelper { protected File mExportFile; - ActionBarActivity mActivity; + FragmentActivity mActivity; - public ExportHelper(ActionBarActivity activity) { + public ExportHelper(FragmentActivity activity) { super(); this.mActivity = activity; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java index 90afd3bc0..c0483ad04 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java @@ -125,7 +125,7 @@ public class Iso7816TLV { public static Iso7816TLV[] readList(byte[] data, boolean recursive) throws IOException { ByteBuffer buf = ByteBuffer.wrap(data); - ArrayList<Iso7816TLV> result = new ArrayList<Iso7816TLV>(); + ArrayList<Iso7816TLV> result = new ArrayList<>(); // read while data is available. this will fail if there is trailing data! while (buf.hasRemaining()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java index 76ec9f75f..943b913d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java @@ -17,21 +17,6 @@ package org.sufficientlysecure.keychain.util; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Messenger; - -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; -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 java.util.ArrayList; -import java.util.List; - public class KeyUpdateHelper { /* diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java index b4f7c5767..8b165cd57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java @@ -21,9 +21,6 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.Constants; -import java.io.IOException; -import java.io.StreamTokenizer; -import java.io.StringReader; import java.util.Iterator; import java.util.Set; 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 3081021cf..5de682fe6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java @@ -32,9 +32,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; /** * When sending large data (over 1MB) through Androids Binder IPC you get diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 5efd6c419..8d4af58d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -200,7 +200,7 @@ public class Preferences { public String[] getKeyServers() { String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS, Constants.Defaults.KEY_SERVERS); - Vector<String> servers = new Vector<String>(); + Vector<String> servers = new Vector<>(); String chunks[] = rawData.split(","); for (String c : chunks) { String tmp = c.trim(); @@ -281,7 +281,7 @@ public class Preferences { case 3: { // migrate keyserver to hkps String[] serversArray = getKeyServers(); - ArrayList<String> servers = new ArrayList<String>(Arrays.asList(serversArray)); + ArrayList<String> servers = new ArrayList<>(Arrays.asList(serversArray)); ListIterator<String> it = servers.listIterator(); while (it.hasNext()) { String server = it.next(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java index 51e58565f..120b84a3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java @@ -43,16 +43,18 @@ public class ShareHelper { * Put together from some stackoverflow posts... */ public Intent createChooserExcluding(Intent prototype, String title, String[] activityBlacklist) { - // Produced an empty list on Huawei U8860 with Android Version 4.0.3 and weird results on 2.3 + // Produced an empty list on Huawei U8860 with Android Version 4.0.3 // TODO: test on 4.1, 4.2, 4.3, only tested on 4.4 - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // Disabled on 5.0 because using EXTRA_INITIAL_INTENTS prevents the usage based sorting + // introduced in 5.0: https://medium.com/@xXxXxXxXxXam/how-lollipops-share-menu-is-organized-d204888f606d + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return Intent.createChooser(prototype, title); } - List<LabeledIntent> targetedShareIntents = new ArrayList<LabeledIntent>(); + List<LabeledIntent> targetedShareIntents = new ArrayList<>(); List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(prototype, 0); - List<ResolveInfo> resInfoListFiltered = new ArrayList<ResolveInfo>(); + List<ResolveInfo> resInfoListFiltered = new ArrayList<>(); if (!resInfoList.isEmpty()) { for (ResolveInfo resolveInfo : resInfoList) { // do not add blacklisted ones diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java index 9946d81aa..7e318281d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java @@ -50,7 +50,7 @@ public class TlsHelper { } } - private static Map<String, byte[]> sStaticCA = new HashMap<String, byte[]>(); + private static Map<String, byte[]> sStaticCA = new HashMap<>(); public static void addStaticCA(String domain, byte[] certificate) { sStaticCA.put(domain, certificate); @@ -120,13 +120,7 @@ public class TlsHelper { urlConnection.setSSLSocketFactory(context.getSocketFactory()); return urlConnection; - } catch (CertificateException e) { - throw new TlsHelperException(e); - } catch (NoSuchAlgorithmException e) { - throw new TlsHelperException(e); - } catch (KeyStoreException e) { - throw new TlsHelperException(e); - } catch (KeyManagementException e) { + } catch (CertificateException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) { throw new TlsHelperException(e); } } diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.png Binary files differdeleted file mode 100644 index e9d2dcb46..000000000 --- a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_collapse.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.png Binary files differdeleted file mode 100644 index 29f4de211..000000000 --- a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_expand.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png Binary files differnew file mode 100644 index 000000000..37931a0ad --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png Binary files differnew file mode 100644 index 000000000..f42a0e2d2 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png Binary files differnew file mode 100644 index 000000000..0fd15563a --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_search_24px.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_search_24px.png Binary files differnew file mode 100644 index 000000000..6f9b343ad --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_search_24px.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png Binary files differnew file mode 100644 index 000000000..35e3b426f --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png Binary files differnew file mode 100644 index 000000000..ed993f35d --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_open_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_open_black_24dp.png Binary files differnew file mode 100644 index 000000000..8ac075245 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_open_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_outline_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_outline_black_24dp.png Binary files differnew file mode 100644 index 000000000..fc019db72 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_outline_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png Binary files differnew file mode 100644 index 000000000..cd16fdd50 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png Binary files differnew file mode 100644 index 000000000..b16209fc1 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png Binary files differnew file mode 100644 index 000000000..c900b8ec7 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.png Binary files differdeleted file mode 100644 index 4ac28f270..000000000 --- a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_collapse.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.png Binary files differdeleted file mode 100644 index bb46bb315..000000000 --- a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_expand.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png Binary files differnew file mode 100644 index 000000000..5b1fd7766 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png Binary files differnew file mode 100644 index 000000000..e91f9048b --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png Binary files differnew file mode 100644 index 000000000..e80681aeb --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_cloud_search_24px.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_cloud_search_24px.png Binary files differnew file mode 100644 index 000000000..7a69993fd --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_cloud_search_24px.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png Binary files differnew file mode 100644 index 000000000..a5ab2c5d3 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png Binary files differnew file mode 100644 index 000000000..73fc3b422 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_open_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_open_black_24dp.png Binary files differnew file mode 100644 index 000000000..9e6d0f0ac --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_open_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_outline_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_outline_black_24dp.png Binary files differnew file mode 100644 index 000000000..1df91994c --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_outline_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png Binary files differnew file mode 100644 index 000000000..235c84f1e --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png Binary files differnew file mode 100644 index 000000000..3405c951d --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png Binary files differnew file mode 100644 index 000000000..5e8781731 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.png Binary files differdeleted file mode 100644 index 60ac6b066..000000000 --- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_collapse.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.png Binary files differdeleted file mode 100644 index 76937f57a..000000000 --- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_expand.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png Binary files differnew file mode 100644 index 000000000..c8187799b --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png Binary files differnew file mode 100644 index 000000000..e5024472a --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png Binary files differnew file mode 100644 index 000000000..76e07f097 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_search_24px.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_search_24px.png Binary files differnew file mode 100644 index 000000000..1f0db264a --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_search_24px.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png Binary files differnew file mode 100644 index 000000000..47c7b52a1 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png Binary files differnew file mode 100644 index 000000000..45d30d999 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_open_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_open_black_24dp.png Binary files differnew file mode 100644 index 000000000..9cd050100 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_open_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_outline_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_outline_black_24dp.png Binary files differnew file mode 100644 index 000000000..ae48a3bf7 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_outline_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png Binary files differnew file mode 100644 index 000000000..5f89fc257 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png Binary files differnew file mode 100644 index 000000000..2b775b646 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png Binary files differnew file mode 100644 index 000000000..ccbdce4ab --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.png Binary files differdeleted file mode 100644 index 76ec594dc..000000000 --- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_collapse.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.png Binary files differdeleted file mode 100644 index 22003198b..000000000 --- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_expand.png +++ /dev/null diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png Binary files differnew file mode 100644 index 000000000..626543b47 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png Binary files differnew file mode 100644 index 000000000..6e03d54cf --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png Binary files differnew file mode 100644 index 000000000..0eb9d8b08 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_search_24px.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_search_24px.png Binary files differnew file mode 100644 index 000000000..852cdc2a6 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_search_24px.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png Binary files differnew file mode 100644 index 000000000..0470e3f02 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png Binary files differnew file mode 100644 index 000000000..aadd04af6 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_open_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_open_black_24dp.png Binary files differnew file mode 100644 index 000000000..529a7724b --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_open_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_outline_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_outline_black_24dp.png Binary files differnew file mode 100644 index 000000000..cf149aa37 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_outline_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png Binary files differnew file mode 100644 index 000000000..72128fe69 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png Binary files differnew file mode 100644 index 000000000..47f0e0d82 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png Binary files differnew file mode 100644 index 000000000..736bde37a --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png Binary files differnew file mode 100644 index 000000000..d12d2e796 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png Binary files differnew file mode 100644 index 000000000..87892840e --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png Binary files differnew file mode 100644 index 000000000..7b2a480a0 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png Binary files differnew file mode 100644 index 000000000..08ae54533 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png Binary files differnew file mode 100644 index 000000000..228b2a982 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_open_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_open_black_24dp.png Binary files differnew file mode 100644 index 000000000..a0fe0156f --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_open_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_outline_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_outline_black_24dp.png Binary files differnew file mode 100644 index 000000000..7460e0894 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_outline_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png Binary files differnew file mode 100644 index 000000000..d271d8e03 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png Binary files differnew file mode 100644 index 000000000..bce161d00 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png Binary files differnew file mode 100644 index 000000000..3451d9855 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png diff --git a/OpenKeychain/src/main/res/layout/actionbar_custom_view_done.xml b/OpenKeychain/src/main/res/layout/actionbar_custom_view_done.xml deleted file mode 100644 index b219038b2..000000000 --- a/OpenKeychain/src/main/res/layout/actionbar_custom_view_done.xml +++ /dev/null @@ -1,26 +0,0 @@ -<!-- - Copyright 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:dividerPadding="12dp" - android:orientation="horizontal" - android:showDividers="end" > - - <include layout="@layout/actionbar_include_done_button" /> - -</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/actionbar_custom_view_done_cancel.xml b/OpenKeychain/src/main/res/layout/actionbar_custom_view_done_cancel.xml deleted file mode 100644 index e9047e759..000000000 --- a/OpenKeychain/src/main/res/layout/actionbar_custom_view_done_cancel.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- - Copyright 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:dividerPadding="12dp" - android:orientation="horizontal" - android:showDividers="middle"> - - <include layout="@layout/actionbar_include_cancel_button" /> - - <include layout="@layout/actionbar_include_done_button" /> - -</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/custom_drawer.xml b/OpenKeychain/src/main/res/layout/custom_drawer.xml new file mode 100644 index 000000000..021226ba3 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/custom_drawer.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:background="@color/colorPrimary"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="@string/app_name" + android:textColor="@color/white" + android:layout_gravity="center_horizontal" /> +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml index 13cf7c225..d6165c1e0 100644 --- a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml +++ b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml @@ -17,7 +17,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginRight="10dp" - android:src="@drawable/ic_action_expand"/> + android:src="@drawable/ic_expand_more_black_24dp"/> <TextView android:id="@+id/foldableText" diff --git a/OpenKeychain/src/main/res/layout/full_screen_dialog.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog.xml new file mode 100644 index 000000000..5eb50da07 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog.xml @@ -0,0 +1,10 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:dividerPadding="12dp" + android:orientation="horizontal" + android:showDividers="middle"> + + <include layout="@layout/full_screen_dialog_done_button" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/full_screen_dialog_2.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog_2.xml new file mode 100644 index 000000000..b1d5efe76 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog_2.xml @@ -0,0 +1,12 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:dividerPadding="12dp" + android:orientation="horizontal" + android:showDividers="middle"> + + <include layout="@layout/full_screen_dialog_2_cancel_button" /> + + <include layout="@layout/full_screen_dialog_2_done_button" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/actionbar_include_cancel_button.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog_2_cancel_button.xml index ec27e394a..7c2c2a62d 100644 --- a/OpenKeychain/src/main/res/layout/actionbar_include_cancel_button.xml +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog_2_cancel_button.xml @@ -1,19 +1,3 @@ -<!-- - Copyright 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/actionbar_cancel" style="@style/Widget.AppCompat.ActionButton" @@ -30,12 +14,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:drawableLeft="@drawable/ic_action_cancel" + android:drawableLeft="@drawable/ic_close_white_24dp" android:drawablePadding="8dp" android:gravity="center_vertical" android:paddingRight="20dp" android:filterTouchesWhenObscured="true" style="@style/Widget.AppCompat.Light.ActionBar.TabText" + android:textAllCaps="true" + android:textSize="14sp" android:text="Cancel (set in-code!)" /> </FrameLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/actionbar_include_done_button.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog_2_done_button.xml index 2590f272c..cd24a1e6d 100644 --- a/OpenKeychain/src/main/res/layout/actionbar_include_done_button.xml +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog_2_done_button.xml @@ -1,19 +1,3 @@ -<!-- - Copyright 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/actionbar_done" style="@style/Widget.AppCompat.ActionButton" @@ -30,12 +14,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:drawableLeft="@drawable/ic_action_done" + android:drawableLeft="@drawable/ic_check_white_24dp" android:drawablePadding="8dp" android:gravity="center_vertical" android:paddingRight="20dp" android:filterTouchesWhenObscured="true" style="@style/Widget.AppCompat.Light.ActionBar.TabText" + android:textAllCaps="true" + android:textSize="14sp" android:text="Done (set in-code!)" /> </FrameLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/full_screen_dialog_done_button.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog_done_button.xml new file mode 100644 index 000000000..49018fee1 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog_done_button.xml @@ -0,0 +1,25 @@ +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/full_screen_dialog_done" + style="@style/Widget.AppCompat.ActionButton" + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <!-- + android:filterTouchesWhenObscured="true" to prevent Touch-Event Hijacking + https://blog.lookout.com/blog/2010/12/09/android-touch-event-hijacking/ + --> + <TextView + android:id="@+id/full_screen_dialog_done_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center" + android:gravity="center_vertical" + android:paddingRight="16dp" + android:paddingEnd="16dp" + style="@style/Widget.AppCompat.Light.ActionBar.TabText" + android:textAllCaps="true" + android:textSize="14sp" + android:filterTouchesWhenObscured="true" + android:text="Done (set in-code!)" /> + +</FrameLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/full_screen_dialog_old.xml b/OpenKeychain/src/main/res/layout/full_screen_dialog_old.xml new file mode 100644 index 000000000..ed375094f --- /dev/null +++ b/OpenKeychain/src/main/res/layout/full_screen_dialog_old.xml @@ -0,0 +1,10 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:dividerPadding="12dp" + android:orientation="horizontal" + android:showDividers="end" > + + <include layout="@layout/full_screen_dialog_2_done_button" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml index f61172a0a..8a682badc 100644 --- a/OpenKeychain/src/main/res/menu/key_list.xml +++ b/OpenKeychain/src/main/res/menu/key_list.xml @@ -11,13 +11,12 @@ <item android:id="@+id/menu_key_list_search_cloud" - android:icon="@drawable/ic_action_search_cloud" + android:icon="@drawable/ic_cloud_search_24px" android:title="@string/menu_search_cloud" app:showAsAction="ifRoom|withText" /> <item android:id="@+id/menu_key_list_add" - android:icon="@drawable/ic_action_qr_code" android:title="@string/import_qr_code_button" app:showAsAction="ifRoom|withText" /> diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index de2a77f62..1151644d8 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -20,7 +20,7 @@ <string name="title_preferences">"Settings"</string> <string name="title_cloud_search_preferences">"Cloud Search Preferences"</string> <string name="title_api_registered_apps">"Apps"</string> - <string name="title_key_server_preference">"Keyserver Preference"</string> + <string name="title_key_server_preference">"Keyservers"</string> <string name="title_change_passphrase">"Change Passphrase"</string> <string name="title_share_fingerprint_with">"Share fingerprint with…"</string> <string name="title_share_key">"Share key with…"</string> @@ -41,6 +41,7 @@ <string name="title_create_key">"Create Key"</string> <string name="title_exchange_keys">"Exchange Keys"</string> <string name="title_advanced_key_info">"Advanced Key Info"</string> + <string name="title_keys">"Keys"</string> <!-- section --> <string name="section_user_ids">"Identities"</string> @@ -826,6 +827,7 @@ <!-- modifySecretKeyRing --> <string name="msg_mr">"Modifying keyring %s"</string> + <string name="msg_mf_error_divert_serial">"The serial number of a divert-to-card key must be 16 bytes! This is a programming error, please file a bug report!"</string> <string name="msg_mf_error_encode">"Encoding exception!"</string> <string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string> <string name="msg_mf_error_keyid">"No key ID. This is an internal error, please file a bug report!"</string> @@ -833,6 +835,7 @@ <string name="msg_mf_error_master_none">"No master certificate found to operate on! (All revoked?)"</string> <string name="msg_mf_error_noexist_primary">"Bad primary user ID specified!"</string> <string name="msg_mf_error_noexist_revoke">"Bad user ID for revocation specified!"</string> + <string name="msg_mf_error_restricted">"Tried to execute restricted operation without passphrase! This is a programming error, please file a bug report!"</string> <string name="msg_mf_error_revoked_primary">"Revoked user IDs cannot be primary!"</string> <string name="msg_mf_error_null_expiry">"Expiry time cannot be "same as before" on subkey creation. This is a programming error, please file a bug report!"</string> <string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string> @@ -905,6 +908,13 @@ <string name="msg_ed_fetching">"Fetching key to modify (%s)"</string> <string name="msg_ed_success">"Key operation successful"</string> + <!-- Promote key --> + <string name="msg_pr">"Promoting public key to secret key"</string> + <string name="msg_pr_error_already_secret">"Key is already a secret key!"</string> + <string name="msg_pr_error_key_not_found">"Key not found!"</string> + <string name="msg_pr_fetching">"Fetching key to modify (%s)"</string> + <string name="msg_pr_success">"Key successfully promoted"</string> + <!-- Other messages used in OperationLogs --> <string name="msg_ek_error_divert">"Editing of NFC keys is not (yet) supported!"</string> <string name="msg_ek_error_dummy">"Cannot edit keyring with stripped master key!"</string> @@ -914,6 +924,7 @@ <string name="msg_dc_askip_no_key">"Data not encrypted with known key, skipping…"</string> <string name="msg_dc_askip_not_allowed">"Data not encrypted with allowed key, skipping…"</string> <string name="msg_dc_asym">"Found block of asymmetrically encrypted data for key %s"</string> + <string name="msg_dc_charset">"Found charset header: '%s'"</string> <string name="msg_dc_clear_data">"Processing literal data"</string> <string name="msg_dc_clear_decompress">"Unpacking compressed data"</string> <string name="msg_dc_clear_meta_file">"Filename: %s"</string> @@ -1012,6 +1023,7 @@ <string name="msg_import_fingerprint_ok">"Fingerprint check OK"</string> <string name="msg_import_merge">"Merging retrieved data"</string> <string name="msg_import_error">"Import operation failed!"</string> + <string name="msg_import_error_io">"Import operation failed due to i/o error!"</string> <string name="msg_import_partial">"Import operation successful, with errors!"</string> <string name="msg_import_success">"Import operation successful!"</string> diff --git a/OpenKeychain/src/main/res/values/themes.xml b/OpenKeychain/src/main/res/values/themes.xml index 602c85247..3b7d66963 100644 --- a/OpenKeychain/src/main/res/values/themes.xml +++ b/OpenKeychain/src/main/res/values/themes.xml @@ -9,6 +9,19 @@ <item name="android:windowNoTitle">true</item> <item name="windowActionBar">false</item> <item name="searchViewStyle">@style/MySearchViewStyle</item> + <item name="colorAccent">@color/accent</item> + + <!-- Navigation Drawer library --> + <item name="drawerType">@integer/DRAWERTYPE_CUSTOM</item> + <item name="theme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item> + <item name="popupTheme">@style/Base.V21.Theme.AppCompat.Light.Dialog</item> + <item name="drawerColor">#fafafa</item> + <item name="singleAccount">false</item> + <item name="sectionStyle">@style/MaterialSectionTheme.Light</item> + <item name="subheaderStyle">@style/MaterialSubheaderTheme.Light</item> + <item name="multipaneSupport">false</item> + <item name="rippleBackport">false</item> + <item name="uniqueToolbarColor">false</item> </style> <!-- http://android-developers.blogspot.de/2014/10/appcompat-v21-material-design-for-pre.html --> @@ -18,7 +31,7 @@ <!-- Background for the actions section (e.g. voice, submit) --> <!--<item name="submitBackground">...</item>--> <!-- Close button icon --> - <!--<item name="closeIcon">...</item>--> + <item name="closeIcon">@drawable/ic_close_white_24dp</item> <!-- Search button icon --> <!--<item name="searchIcon">...</item>--> <!-- Go/commit button icon --> |