Merge branch 'development' into detached-sigs-api
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
This commit is contained in:
@@ -31,10 +31,7 @@
|
||||
For OI Filemanager it makes no difference, gpg files can't be associated
|
||||
-->
|
||||
|
||||
<!-- Specified in build.gradle -->
|
||||
<!--<uses-sdk-->
|
||||
<!--android:minSdkVersion="9"-->
|
||||
<!--android:targetSdkVersion="19" />-->
|
||||
<!-- SDK levels are specified in build.gradle -->
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.wifi"
|
||||
@@ -421,7 +418,7 @@
|
||||
android:label="@string/title_advanced_key_info">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.PreferencesActivity"
|
||||
android:name=".ui.SettingsActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_preferences">
|
||||
<intent-filter>
|
||||
@@ -434,7 +431,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.PreferencesKeyServerActivity"
|
||||
android:name=".ui.SettingsKeyServerActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_key_server_preference"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -137,7 +137,7 @@ public class ImportExportOperation extends BaseOperation {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -343,6 +343,18 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_IP_UID_REORDER(LogLevel.DEBUG, R.string.msg_ip_uid_reorder),
|
||||
MSG_IP_UID_PROCESSING (LogLevel.DEBUG, R.string.msg_ip_uid_processing),
|
||||
MSG_IP_UID_REVOKED (LogLevel.DEBUG, R.string.msg_ip_uid_revoked),
|
||||
MSG_IP_UAT_CLASSIFYING (LogLevel.DEBUG, R.string.msg_ip_uat_classifying),
|
||||
MSG_IP_UAT_PROCESSING_IMAGE (LogLevel.DEBUG, R.string.msg_ip_uat_processing_image),
|
||||
MSG_IP_UAT_PROCESSING_UNKNOWN (LogLevel.DEBUG, R.string.msg_ip_uat_processing_unknown),
|
||||
MSG_IP_UAT_REVOKED (LogLevel.DEBUG, R.string.msg_ip_uat_revoked),
|
||||
MSG_IP_UAT_CERT_BAD (LogLevel.WARN, R.string.msg_ip_uat_cert_bad),
|
||||
MSG_IP_UAT_CERT_OLD (LogLevel.DEBUG, R.string.msg_ip_uat_cert_old),
|
||||
MSG_IP_UAT_CERT_NONREVOKE (LogLevel.DEBUG, R.string.msg_ip_uat_cert_nonrevoke),
|
||||
MSG_IP_UAT_CERT_NEW (LogLevel.DEBUG, R.string.msg_ip_uat_cert_new),
|
||||
MSG_IP_UAT_CERT_ERROR (LogLevel.WARN, R.string.msg_ip_uat_cert_error),
|
||||
MSG_IP_UAT_CERTS_UNKNOWN (LogLevel.DEBUG, R.plurals.msg_ip_uat_certs_unknown),
|
||||
MSG_IP_UAT_CERT_GOOD_REVOKE (LogLevel.DEBUG, R.string.msg_ip_uat_cert_good_revoke),
|
||||
MSG_IP_UAT_CERT_GOOD (LogLevel.DEBUG, R.string.msg_ip_uat_cert_good),
|
||||
|
||||
// import secret
|
||||
MSG_IS(LogLevel.START, R.string.msg_is),
|
||||
@@ -416,6 +428,21 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_KC_UID_REVOKE_OLD (LogLevel.DEBUG, R.string.msg_kc_uid_revoke_old),
|
||||
MSG_KC_UID_REMOVE (LogLevel.DEBUG, R.string.msg_kc_uid_remove),
|
||||
MSG_KC_UID_WARN_ENCODING (LogLevel.WARN, R.string.msg_kc_uid_warn_encoding),
|
||||
MSG_KC_UAT_JPEG (LogLevel.DEBUG, R.string.msg_kc_uat_jpeg),
|
||||
MSG_KC_UAT_UNKNOWN (LogLevel.DEBUG, R.string.msg_kc_uat_unknown),
|
||||
MSG_KC_UAT_BAD_ERR (LogLevel.WARN, R.string.msg_kc_uat_bad_err),
|
||||
MSG_KC_UAT_BAD_LOCAL (LogLevel.WARN, R.string.msg_kc_uat_bad_local),
|
||||
MSG_KC_UAT_BAD_TIME (LogLevel.WARN, R.string.msg_kc_uat_bad_time),
|
||||
MSG_KC_UAT_BAD_TYPE (LogLevel.WARN, R.string.msg_kc_uat_bad_type),
|
||||
MSG_KC_UAT_BAD (LogLevel.WARN, R.string.msg_kc_uat_bad),
|
||||
MSG_KC_UAT_CERT_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_cert_dup),
|
||||
MSG_KC_UAT_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_dup),
|
||||
MSG_KC_UAT_FOREIGN (LogLevel.DEBUG, R.string.msg_kc_uat_foreign),
|
||||
MSG_KC_UAT_NO_CERT (LogLevel.DEBUG, R.string.msg_kc_uat_no_cert),
|
||||
MSG_KC_UAT_REVOKE_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_revoke_dup),
|
||||
MSG_KC_UAT_REVOKE_OLD (LogLevel.DEBUG, R.string.msg_kc_uat_revoke_old),
|
||||
MSG_KC_UAT_REMOVE (LogLevel.DEBUG, R.string.msg_kc_uat_remove),
|
||||
MSG_KC_UAT_WARN_ENCODING (LogLevel.WARN, R.string.msg_kc_uat_warn_encoding),
|
||||
|
||||
|
||||
// keyring consolidation
|
||||
@@ -446,6 +473,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),
|
||||
@@ -458,6 +486,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),
|
||||
@@ -480,6 +509,9 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_MF_UID_PRIMARY (LogLevel.INFO, R.string.msg_mf_uid_primary),
|
||||
MSG_MF_UID_REVOKE (LogLevel.INFO, R.string.msg_mf_uid_revoke),
|
||||
MSG_MF_UID_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_mf_uid_error_empty),
|
||||
MSG_MF_UAT_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_mf_uat_error_empty),
|
||||
MSG_MF_UAT_ADD_IMAGE (LogLevel.INFO, R.string.msg_mf_uat_add_image),
|
||||
MSG_MF_UAT_ADD_UNKNOWN (LogLevel.INFO, R.string.msg_mf_uat_add_unknown),
|
||||
MSG_MF_UNLOCK_ERROR (LogLevel.ERROR, R.string.msg_mf_unlock_error),
|
||||
MSG_MF_UNLOCK (LogLevel.DEBUG, R.string.msg_mf_unlock),
|
||||
|
||||
@@ -516,6 +548,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),
|
||||
@@ -696,7 +735,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) {
|
||||
@@ -721,7 +760,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;
|
||||
}
|
||||
@@ -730,7 +769,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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
@@ -134,7 +135,7 @@ public class PgpKeyOperation {
|
||||
public PgpKeyOperation(Progressable progress) {
|
||||
super();
|
||||
if (progress != null) {
|
||||
mProgress = new Stack<Progressable>();
|
||||
mProgress = new Stack<>();
|
||||
mProgress.push(progress);
|
||||
}
|
||||
}
|
||||
@@ -287,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);
|
||||
@@ -388,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) {
|
||||
@@ -428,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();
|
||||
@@ -478,7 +485,7 @@ public class PgpKeyOperation {
|
||||
PGPPublicKey modifiedPublicKey = masterPublicKey;
|
||||
|
||||
// 2a. Add certificates for new user ids
|
||||
subProgressPush(15, 25);
|
||||
subProgressPush(15, 23);
|
||||
for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
|
||||
|
||||
progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
|
||||
@@ -495,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);
|
||||
@@ -522,8 +529,37 @@ public class PgpKeyOperation {
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
// 2b. Add revocations for revoked user ids
|
||||
subProgressPush(25, 40);
|
||||
// 2b. Add certificates for new user ids
|
||||
subProgressPush(23, 32);
|
||||
for (int i = 0; i < saveParcel.mAddUserAttribute.size(); i++) {
|
||||
|
||||
progress(R.string.progress_modify_adduat, (i - 1) * (100 / saveParcel.mAddUserAttribute.size()));
|
||||
WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i);
|
||||
|
||||
switch (attribute.getType()) {
|
||||
// the 'none' type must not succeed
|
||||
case WrappedUserAttribute.UAT_NONE:
|
||||
log.add(LogType.MSG_MF_UAT_ERROR_EMPTY, indent);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
case WrappedUserAttribute.UAT_IMAGE:
|
||||
log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent);
|
||||
break;
|
||||
default:
|
||||
log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent);
|
||||
break;
|
||||
}
|
||||
|
||||
PGPUserAttributeSubpacketVector vector = attribute.getVector();
|
||||
|
||||
// generate and add new certificate
|
||||
PGPSignature cert = generateUserAttributeSignature(masterPrivateKey,
|
||||
masterPublicKey, vector);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
// 2c. Add revocations for revoked user ids
|
||||
subProgressPush(32, 40);
|
||||
for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
|
||||
|
||||
progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
|
||||
@@ -685,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())) {
|
||||
@@ -775,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++) {
|
||||
@@ -907,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,
|
||||
@@ -1174,6 +1274,26 @@ public class PgpKeyOperation {
|
||||
return sGen.generateCertification(userId, pKey);
|
||||
}
|
||||
|
||||
private static PGPSignature generateUserAttributeSignature(
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey,
|
||||
PGPUserAttributeSubpacketVector vector)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
{
|
||||
/* critical subpackets: we consider those important for a modern pgp implementation */
|
||||
hashedPacketsGen.setSignatureCreationTime(true, new Date());
|
||||
}
|
||||
|
||||
sGen.setHashedSubpackets(hashedPacketsGen.generate());
|
||||
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
|
||||
return sGen.generateCertification(vector, pKey);
|
||||
}
|
||||
|
||||
private static PGPSignature generateRevocationSignature(
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp;
|
||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
|
||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||
import org.spongycastle.bcpg.UserAttributeSubpacketTags;
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.PGPKeyRing;
|
||||
import org.spongycastle.openpgp.PGPObjectFactory;
|
||||
@@ -30,6 +31,7 @@ import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureList;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
@@ -443,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);
|
||||
|
||||
@@ -468,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();
|
||||
|
||||
@@ -605,6 +607,170 @@ public class UncachedKeyRing {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<PGPUserAttributeSubpacketVector> processedUserAttributes = new ArrayList<>();
|
||||
for (PGPUserAttributeSubpacketVector userAttribute :
|
||||
new IterableIterator<PGPUserAttributeSubpacketVector>(masterKey.getUserAttributes())) {
|
||||
|
||||
if (userAttribute.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) {
|
||||
log.add(LogType.MSG_KC_UAT_JPEG, indent);
|
||||
} else {
|
||||
log.add(LogType.MSG_KC_UAT_UNKNOWN, indent);
|
||||
}
|
||||
|
||||
try {
|
||||
indent += 1;
|
||||
|
||||
// check for duplicate user attributes
|
||||
if (processedUserAttributes.contains(userAttribute)) {
|
||||
log.add(LogType.MSG_KC_UAT_DUP, indent);
|
||||
// strip out the first found user id with this name
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute);
|
||||
}
|
||||
processedUserAttributes.add(userAttribute);
|
||||
|
||||
PGPSignature selfCert = null;
|
||||
revocation = null;
|
||||
|
||||
// look through signatures for this specific user id
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute);
|
||||
if (signaturesIt != null) {
|
||||
for (PGPSignature zert : new IterableIterator<>(signaturesIt)) {
|
||||
WrappedSignature cert = new WrappedSignature(zert);
|
||||
long certId = cert.getKeyId();
|
||||
|
||||
int type = zert.getSignatureType();
|
||||
if (type != PGPSignature.DEFAULT_CERTIFICATION
|
||||
&& type != PGPSignature.NO_CERTIFICATION
|
||||
&& type != PGPSignature.CASUAL_CERTIFICATION
|
||||
&& type != PGPSignature.POSITIVE_CERTIFICATION
|
||||
&& type != PGPSignature.CERTIFICATION_REVOCATION) {
|
||||
log.add(LogType.MSG_KC_UAT_BAD_TYPE,
|
||||
indent, "0x" + Integer.toString(zert.getSignatureType(), 16));
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cert.getCreationTime().after(nowPlusOneDay)) {
|
||||
// Creation date in the future? No way!
|
||||
log.add(LogType.MSG_KC_UAT_BAD_TIME, indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cert.isLocal()) {
|
||||
// Creation date in the future? No way!
|
||||
log.add(LogType.MSG_KC_UAT_BAD_LOCAL, indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a foreign signature, ...
|
||||
if (certId != masterKeyId) {
|
||||
// never mind any further for public keys, but remove them from secret ones
|
||||
if (isSecret()) {
|
||||
log.add(LogType.MSG_KC_UAT_FOREIGN,
|
||||
indent, KeyFormattingUtils.convertKeyIdToHex(certId));
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, first make sure it checks out
|
||||
try {
|
||||
cert.init(masterKey);
|
||||
if (!cert.verifySignature(masterKey, userAttribute)) {
|
||||
log.add(LogType.MSG_KC_UAT_BAD,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
continue;
|
||||
}
|
||||
} catch (PgpGeneralException e) {
|
||||
log.add(LogType.MSG_KC_UAT_BAD_ERR,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
badCerts += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PGPSignature.DEFAULT_CERTIFICATION:
|
||||
case PGPSignature.NO_CERTIFICATION:
|
||||
case PGPSignature.CASUAL_CERTIFICATION:
|
||||
case PGPSignature.POSITIVE_CERTIFICATION:
|
||||
if (selfCert == null) {
|
||||
selfCert = zert;
|
||||
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
|
||||
log.add(LogType.MSG_KC_UAT_CERT_DUP,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, selfCert);
|
||||
redundantCerts += 1;
|
||||
selfCert = zert;
|
||||
} else {
|
||||
log.add(LogType.MSG_KC_UAT_CERT_DUP,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
redundantCerts += 1;
|
||||
}
|
||||
// If there is a revocation certificate, and it's older than this, drop it
|
||||
if (revocation != null
|
||||
&& revocation.getCreationTime().before(selfCert.getCreationTime())) {
|
||||
log.add(LogType.MSG_KC_UAT_REVOKE_OLD,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation);
|
||||
revocation = null;
|
||||
redundantCerts += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PGPSignature.CERTIFICATION_REVOCATION:
|
||||
// If this is older than the (latest) self cert, drop it
|
||||
if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
|
||||
log.add(LogType.MSG_KC_UAT_REVOKE_OLD,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
redundantCerts += 1;
|
||||
continue;
|
||||
}
|
||||
// first revocation? remember it.
|
||||
if (revocation == null) {
|
||||
revocation = zert;
|
||||
// more revocations? at least one is superfluous, then.
|
||||
} else if (revocation.getCreationTime().before(cert.getCreationTime())) {
|
||||
log.add(LogType.MSG_KC_UAT_REVOKE_DUP,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation);
|
||||
redundantCerts += 1;
|
||||
revocation = zert;
|
||||
} else {
|
||||
log.add(LogType.MSG_KC_UAT_REVOKE_DUP,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
|
||||
redundantCerts += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid certificate (if only a revocation) remains, drop it
|
||||
if (selfCert == null && revocation == null) {
|
||||
log.add(LogType.MSG_KC_UAT_REMOVE,
|
||||
indent);
|
||||
modified = PGPPublicKey.removeCertification(modified, userAttribute);
|
||||
}
|
||||
|
||||
} finally {
|
||||
indent -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replace modified key in the keyring
|
||||
ring = replacePublicKey(ring, modified);
|
||||
indent -= 1;
|
||||
@@ -612,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())) {
|
||||
@@ -852,8 +1018,8 @@ public class UncachedKeyRing {
|
||||
/** This operation merges information from a different keyring, returning a combined
|
||||
* UncachedKeyRing.
|
||||
*
|
||||
* The combined keyring contains the subkeys and user ids of both input keyrings, but it does
|
||||
* not necessarily have the canonicalized property.
|
||||
* The combined keyring contains the subkeys, user ids and user attributes of both input
|
||||
* keyrings, but it does not necessarily have the canonicalized property.
|
||||
*
|
||||
* @param other The UncachedKeyRing to merge. Must not be empty, and of the same masterKeyId
|
||||
* @return A consolidated UncachedKeyRing with the data of both input keyrings. Same type as
|
||||
@@ -876,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) {
|
||||
@@ -958,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;
|
||||
@@ -973,6 +1139,32 @@ public class UncachedKeyRing {
|
||||
modified = PGPPublicKey.addCertification(modified, rawUserId, cert);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy over all user attribute certificates
|
||||
for (PGPUserAttributeSubpacketVector vector :
|
||||
new IterableIterator<PGPUserAttributeSubpacketVector>(key.getUserAttributes())) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<PGPSignature> signaturesIt = key.getSignaturesForUserAttribute(vector);
|
||||
// no signatures for this user attribute attribute, skip it
|
||||
if (signaturesIt == null) {
|
||||
continue;
|
||||
}
|
||||
for (PGPSignature cert : new IterableIterator<>(signaturesIt)) {
|
||||
// Don't merge foreign stuff into secret keys
|
||||
if (cert.getKeyID() != masterKeyId && isSecret()) {
|
||||
continue;
|
||||
}
|
||||
byte[] encoded = cert.getEncoded();
|
||||
// Known cert, skip it
|
||||
if (certs.contains(encoded)) {
|
||||
continue;
|
||||
}
|
||||
newCerts += 1;
|
||||
certs.add(encoded);
|
||||
modified = PGPPublicKey.addCertification(modified, vector, cert);
|
||||
}
|
||||
}
|
||||
|
||||
// If anything changed, save the updated (sub)key
|
||||
if (modified != resultKey) {
|
||||
result = replacePublicKey(result, modified);
|
||||
|
||||
@@ -20,10 +20,10 @@ 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;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
@@ -135,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
|
||||
@@ -199,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));
|
||||
@@ -208,13 +208,22 @@ 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);
|
||||
}
|
||||
return userIds;
|
||||
}
|
||||
|
||||
public ArrayList<WrappedUserAttribute> getUnorderedUserAttributes() {
|
||||
ArrayList<WrappedUserAttribute> userAttributes = new ArrayList<>();
|
||||
for (PGPUserAttributeSubpacketVector userAttribute :
|
||||
new IterableIterator<PGPUserAttributeSubpacketVector>(mPublicKey.getUserAttributes())) {
|
||||
userAttributes.add(new WrappedUserAttribute(userAttribute));
|
||||
}
|
||||
return userAttributes;
|
||||
}
|
||||
|
||||
public boolean isElGamalEncrypt() {
|
||||
return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT;
|
||||
}
|
||||
@@ -270,33 +279,83 @@ public class UncachedPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<WrappedSignature> getSignaturesForUserAttribute(WrappedUserAttribute attribute) {
|
||||
final Iterator<PGPSignature> it = mPublicKey.getSignaturesForUserAttribute(attribute.getVector());
|
||||
if (it != null) {
|
||||
return new Iterator<WrappedSignature>() {
|
||||
public void remove() {
|
||||
it.remove();
|
||||
}
|
||||
public WrappedSignature next() {
|
||||
return new WrappedSignature(it.next());
|
||||
}
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get all key usage flags.
|
||||
* If at least one key flag subpacket is present return these. If no
|
||||
* subpacket is present it returns null.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ import org.spongycastle.openpgp.PGPObjectFactory;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureList;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
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;
|
||||
@@ -79,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;
|
||||
}
|
||||
@@ -199,12 +199,23 @@ public class WrappedSignature {
|
||||
}
|
||||
}
|
||||
|
||||
boolean verifySignature(PGPPublicKey key, PGPUserAttributeSubpacketVector attribute) throws PgpGeneralException {
|
||||
try {
|
||||
return mSig.verifyCertification(attribute, key);
|
||||
} catch (PGPException e) {
|
||||
throw new PgpGeneralException("Error!", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean verifySignature(UncachedPublicKey key, byte[] rawUserId) throws PgpGeneralException {
|
||||
return verifySignature(key.getPublicKey(), rawUserId);
|
||||
}
|
||||
public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException {
|
||||
return verifySignature(key.getPublicKey(), uid);
|
||||
}
|
||||
public boolean verifySignature(UncachedPublicKey key, WrappedUserAttribute attribute) throws PgpGeneralException {
|
||||
return verifySignature(key.getPublicKey(), attribute.getVector());
|
||||
}
|
||||
|
||||
public static WrappedSignature fromBytes(byte[] data) {
|
||||
PGPObjectFactory factory = new PGPObjectFactory(data);
|
||||
@@ -243,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
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.pgp;
|
||||
|
||||
import org.spongycastle.bcpg.BCPGInputStream;
|
||||
import org.spongycastle.bcpg.BCPGOutputStream;
|
||||
import org.spongycastle.bcpg.Packet;
|
||||
import org.spongycastle.bcpg.UserAttributePacket;
|
||||
import org.spongycastle.bcpg.UserAttributeSubpacket;
|
||||
import org.spongycastle.bcpg.UserAttributeSubpacketInputStream;
|
||||
import org.spongycastle.bcpg.UserAttributeSubpacketTags;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class WrappedUserAttribute implements Serializable {
|
||||
|
||||
public static final int UAT_NONE = 0;
|
||||
public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE;
|
||||
|
||||
private PGPUserAttributeSubpacketVector mVector;
|
||||
|
||||
WrappedUserAttribute(PGPUserAttributeSubpacketVector vector) {
|
||||
mVector = vector;
|
||||
}
|
||||
|
||||
PGPUserAttributeSubpacketVector getVector() {
|
||||
return mVector;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray();
|
||||
if (subpackets.length > 0) {
|
||||
return subpackets[0].getType();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static WrappedUserAttribute fromSubpacket (int type, byte[] data) {
|
||||
UserAttributeSubpacket subpacket = new UserAttributeSubpacket(type, data);
|
||||
PGPUserAttributeSubpacketVector vector = new PGPUserAttributeSubpacketVector(
|
||||
new UserAttributeSubpacket[] { subpacket });
|
||||
|
||||
return new WrappedUserAttribute(vector);
|
||||
|
||||
}
|
||||
|
||||
public byte[] getEncoded () throws IOException {
|
||||
UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for (UserAttributeSubpacket subpacket : subpackets) {
|
||||
subpacket.encode(out);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static WrappedUserAttribute fromData (byte[] data) throws IOException {
|
||||
UserAttributeSubpacketInputStream in =
|
||||
new UserAttributeSubpacketInputStream(new ByteArrayInputStream(data));
|
||||
ArrayList<UserAttributeSubpacket> list = new ArrayList<UserAttributeSubpacket>();
|
||||
while (in.available() > 0) {
|
||||
list.add(in.readPacket());
|
||||
}
|
||||
UserAttributeSubpacket[] result = new UserAttributeSubpacket[list.size()];
|
||||
list.toArray(result);
|
||||
return new WrappedUserAttribute(
|
||||
new PGPUserAttributeSubpacketVector(result));
|
||||
}
|
||||
|
||||
/** Writes this object to an ObjectOutputStream. */
|
||||
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
BCPGOutputStream bcpg = new BCPGOutputStream(baos);
|
||||
bcpg.writePacket(new UserAttributePacket(mVector.toSubpacketArray()));
|
||||
out.writeObject(baos.toByteArray());
|
||||
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
|
||||
byte[] data = (byte[]) in.readObject();
|
||||
BCPGInputStream bcpg = new BCPGInputStream(new ByteArrayInputStream(data));
|
||||
Packet p = bcpg.readPacket();
|
||||
if ( ! UserAttributePacket.class.isInstance(p)) {
|
||||
throw new IOException("Could not decode UserAttributePacket!");
|
||||
}
|
||||
mVector = new PGPUserAttributeSubpacketVector(((UserAttributePacket) p).getSubpackets());
|
||||
|
||||
}
|
||||
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!WrappedUserAttribute.class.isInstance(o)) {
|
||||
return false;
|
||||
}
|
||||
return mVector.equals(((WrappedUserAttribute) o).mVector);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,9 +51,11 @@ public class KeychainContract {
|
||||
String EXPIRY = "expiry";
|
||||
}
|
||||
|
||||
interface UserIdsColumns {
|
||||
interface UserPacketsColumns {
|
||||
String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID
|
||||
String TYPE = "type"; // not a database id
|
||||
String USER_ID = "user_id"; // not a database id
|
||||
String ATTRIBUTE_DATA = "attribute_data"; // not a database id
|
||||
String RANK = "rank"; // ONLY used for sorting! no key, no nothing!
|
||||
String IS_PRIMARY = "is_primary";
|
||||
String IS_REVOKED = "is_revoked";
|
||||
@@ -105,7 +107,7 @@ public class KeychainContract {
|
||||
public static final String BASE_API_APPS = "api_apps";
|
||||
public static final String PATH_ACCOUNTS = "accounts";
|
||||
|
||||
public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns {
|
||||
public static class KeyRings implements BaseColumns, KeysColumns, UserPacketsColumns {
|
||||
public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID;
|
||||
public static final String IS_REVOKED = KeysColumns.IS_REVOKED;
|
||||
public static final String VERIFIED = CertsColumns.VERIFIED;
|
||||
@@ -225,7 +227,7 @@ public class KeychainContract {
|
||||
|
||||
}
|
||||
|
||||
public static class UserIds implements UserIdsColumns, BaseColumns {
|
||||
public static class UserPackets implements UserPacketsColumns, BaseColumns {
|
||||
public static final String VERIFIED = "verified";
|
||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||
.appendPath(BASE_KEY_RINGS).build();
|
||||
@@ -304,7 +306,7 @@ public class KeychainContract {
|
||||
}
|
||||
|
||||
public static class Certs implements CertsColumns, BaseColumns {
|
||||
public static final String USER_ID = UserIdsColumns.USER_ID;
|
||||
public static final String USER_ID = UserPacketsColumns.USER_ID;
|
||||
public static final String SIGNER_UID = "signer_user_id";
|
||||
|
||||
public static final int UNVERIFIED = 0;
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
|
||||
import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@@ -52,7 +52,7 @@ import java.io.IOException;
|
||||
*/
|
||||
public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
private static final String DATABASE_NAME = "openkeychain.db";
|
||||
private static final int DATABASE_VERSION = 6;
|
||||
private static final int DATABASE_VERSION = 7;
|
||||
static Boolean apgHack = false;
|
||||
private Context mContext;
|
||||
|
||||
@@ -60,7 +60,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
String KEY_RINGS_PUBLIC = "keyrings_public";
|
||||
String KEY_RINGS_SECRET = "keyrings_secret";
|
||||
String KEYS = "keys";
|
||||
String USER_IDS = "user_ids";
|
||||
String USER_PACKETS = "user_ids";
|
||||
String CERTS = "certs";
|
||||
String API_APPS = "api_apps";
|
||||
String API_ACCOUNTS = "api_accounts";
|
||||
@@ -106,18 +106,20 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
|
||||
+ ")";
|
||||
|
||||
private static final String CREATE_USER_IDS =
|
||||
"CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + "("
|
||||
+ UserIdsColumns.MASTER_KEY_ID + " INTEGER, "
|
||||
+ UserIdsColumns.USER_ID + " TEXT, "
|
||||
private static final String CREATE_USER_PACKETS =
|
||||
"CREATE TABLE IF NOT EXISTS " + Tables.USER_PACKETS + "("
|
||||
+ UserPacketsColumns.MASTER_KEY_ID + " INTEGER, "
|
||||
+ UserPacketsColumns.TYPE + " INT, "
|
||||
+ UserPacketsColumns.USER_ID + " TEXT, "
|
||||
+ UserPacketsColumns.ATTRIBUTE_DATA + " BLOB, "
|
||||
|
||||
+ UserIdsColumns.IS_PRIMARY + " INTEGER, "
|
||||
+ UserIdsColumns.IS_REVOKED + " INTEGER, "
|
||||
+ UserIdsColumns.RANK+ " INTEGER, "
|
||||
+ UserPacketsColumns.IS_PRIMARY + " INTEGER, "
|
||||
+ UserPacketsColumns.IS_REVOKED + " INTEGER, "
|
||||
+ UserPacketsColumns.RANK+ " INTEGER, "
|
||||
|
||||
+ "PRIMARY KEY(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.USER_ID + "), "
|
||||
+ "UNIQUE (" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + "), "
|
||||
+ "FOREIGN KEY(" + UserIdsColumns.MASTER_KEY_ID + ") REFERENCES "
|
||||
+ "PRIMARY KEY(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.USER_ID + "), "
|
||||
+ "UNIQUE (" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + "), "
|
||||
+ "FOREIGN KEY(" + UserPacketsColumns.MASTER_KEY_ID + ") REFERENCES "
|
||||
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
|
||||
+ ")";
|
||||
|
||||
@@ -138,7 +140,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
+ "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ") REFERENCES "
|
||||
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE,"
|
||||
+ "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ") REFERENCES "
|
||||
+ Tables.USER_IDS + "(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + ") ON DELETE CASCADE"
|
||||
+ Tables.USER_PACKETS + "(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + ") ON DELETE CASCADE"
|
||||
+ ")";
|
||||
|
||||
private static final String CREATE_API_APPS =
|
||||
@@ -189,7 +191,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
db.execSQL(CREATE_KEYRINGS_PUBLIC);
|
||||
db.execSQL(CREATE_KEYRINGS_SECRET);
|
||||
db.execSQL(CREATE_KEYS);
|
||||
db.execSQL(CREATE_USER_IDS);
|
||||
db.execSQL(CREATE_USER_PACKETS);
|
||||
db.execSQL(CREATE_CERTS);
|
||||
db.execSQL(CREATE_API_APPS);
|
||||
db.execSQL(CREATE_API_APPS_ACCOUNTS);
|
||||
@@ -238,6 +240,9 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
case 5:
|
||||
// do consolidate for 3.0 beta3
|
||||
// fall through
|
||||
case 6:
|
||||
db.execSQL("ALTER TABLE user_ids ADD COLUMN type INTEGER");
|
||||
db.execSQL("ALTER TABLE user_ids ADD COLUMN attribute_data BLOB");
|
||||
}
|
||||
|
||||
// always do consolidate after upgrade
|
||||
|
||||
@@ -37,7 +37,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
@@ -205,7 +206,7 @@ public class KeychainProvider extends ContentProvider {
|
||||
return Keys.CONTENT_TYPE;
|
||||
|
||||
case KEY_RING_USER_IDS:
|
||||
return UserIds.CONTENT_TYPE;
|
||||
return UserPackets.CONTENT_TYPE;
|
||||
|
||||
case KEY_RING_SECRET:
|
||||
return KeyRings.CONTENT_ITEM_TYPE;
|
||||
@@ -247,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);
|
||||
@@ -262,7 +263,7 @@ public class KeychainProvider extends ContentProvider {
|
||||
projectionMap.put(KeyRings.EXPIRY, Tables.KEYS + "." + Keys.EXPIRY);
|
||||
projectionMap.put(KeyRings.ALGORITHM, Tables.KEYS + "." + Keys.ALGORITHM);
|
||||
projectionMap.put(KeyRings.FINGERPRINT, Tables.KEYS + "." + Keys.FINGERPRINT);
|
||||
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
||||
projectionMap.put(KeyRings.USER_ID, UserPackets.USER_ID);
|
||||
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
||||
projectionMap.put(KeyRings.PUBKEY_DATA,
|
||||
Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA
|
||||
@@ -296,11 +297,12 @@ public class KeychainProvider extends ContentProvider {
|
||||
|
||||
qb.setTables(
|
||||
Tables.KEYS
|
||||
+ " INNER JOIN " + Tables.USER_IDS + " ON ("
|
||||
+ " INNER JOIN " + Tables.USER_PACKETS + " ON ("
|
||||
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||
+ " = "
|
||||
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
|
||||
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0"
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||
// we KNOW that the rank zero user packet is a user id!
|
||||
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = 0"
|
||||
+ ") LEFT JOIN " + Tables.CERTS + " ON ("
|
||||
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||
+ " = "
|
||||
@@ -376,7 +378,7 @@ public class KeychainProvider extends ContentProvider {
|
||||
String subkey = Long.valueOf(uri.getLastPathSegment()).toString();
|
||||
qb.appendWhere(" AND EXISTS ("
|
||||
+ " SELECT 1 FROM " + Tables.KEYS + " AS tmp"
|
||||
+ " WHERE tmp." + UserIds.MASTER_KEY_ID
|
||||
+ " WHERE tmp." + UserPackets.MASTER_KEY_ID
|
||||
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||
+ " AND tmp." + Keys.KEY_ID + " = " + subkey + ""
|
||||
+ ")");
|
||||
@@ -398,15 +400,15 @@ public class KeychainProvider extends ContentProvider {
|
||||
if (i != 0) {
|
||||
emailWhere += " OR ";
|
||||
}
|
||||
emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
|
||||
emailWhere += "tmp." + UserPackets.USER_ID + " LIKE ";
|
||||
// match '*<email>', so it has to be at the *end* of the user id
|
||||
emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
|
||||
gotCondition = true;
|
||||
}
|
||||
if(gotCondition) {
|
||||
qb.appendWhere(" AND EXISTS ("
|
||||
+ " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp"
|
||||
+ " WHERE tmp." + UserIds.MASTER_KEY_ID
|
||||
+ " SELECT 1 FROM " + Tables.USER_PACKETS + " AS tmp"
|
||||
+ " WHERE tmp." + UserPackets.MASTER_KEY_ID
|
||||
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||
+ " AND (" + emailWhere + ")"
|
||||
+ ")");
|
||||
@@ -420,7 +422,7 @@ public class KeychainProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(sortOrder)) {
|
||||
sortOrder = Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
|
||||
sortOrder = Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC";
|
||||
}
|
||||
|
||||
// uri to watch is all /key_rings/
|
||||
@@ -430,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);
|
||||
@@ -458,37 +460,45 @@ public class KeychainProvider extends ContentProvider {
|
||||
|
||||
case KEY_RINGS_USER_IDS:
|
||||
case KEY_RING_USER_IDS: {
|
||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||
projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id");
|
||||
projectionMap.put(UserIds.MASTER_KEY_ID, Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID);
|
||||
projectionMap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
|
||||
projectionMap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK);
|
||||
projectionMap.put(UserIds.IS_PRIMARY, Tables.USER_IDS + "." + UserIds.IS_PRIMARY);
|
||||
projectionMap.put(UserIds.IS_REVOKED, Tables.USER_IDS + "." + UserIds.IS_REVOKED);
|
||||
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);
|
||||
projectionMap.put(UserPackets.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID);
|
||||
projectionMap.put(UserPackets.ATTRIBUTE_DATA, Tables.USER_PACKETS + "." + UserPackets.ATTRIBUTE_DATA);
|
||||
projectionMap.put(UserPackets.RANK, Tables.USER_PACKETS + "." + UserPackets.RANK);
|
||||
projectionMap.put(UserPackets.IS_PRIMARY, Tables.USER_PACKETS + "." + UserPackets.IS_PRIMARY);
|
||||
projectionMap.put(UserPackets.IS_REVOKED, Tables.USER_PACKETS + "." + UserPackets.IS_REVOKED);
|
||||
// we take the minimum (>0) here, where "1" is "verified by known secret key"
|
||||
projectionMap.put(UserIds.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserIds.VERIFIED);
|
||||
projectionMap.put(UserPackets.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserPackets.VERIFIED);
|
||||
qb.setProjectionMap(projectionMap);
|
||||
|
||||
qb.setTables(Tables.USER_IDS
|
||||
qb.setTables(Tables.USER_PACKETS
|
||||
+ " LEFT JOIN " + Tables.CERTS + " ON ("
|
||||
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = "
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = "
|
||||
+ Tables.CERTS + "." + Certs.MASTER_KEY_ID
|
||||
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = "
|
||||
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = "
|
||||
+ Tables.CERTS + "." + Certs.RANK
|
||||
+ " AND " + Tables.CERTS + "." + Certs.VERIFIED + " > 0"
|
||||
+ ")");
|
||||
groupBy = Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
|
||||
+ ", " + Tables.USER_IDS + "." + UserIds.RANK;
|
||||
groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.RANK;
|
||||
|
||||
// for now, we only respect user ids here, so TYPE must be NULL
|
||||
// TODO expand with KEY_RING_USER_PACKETS query type which lifts this restriction
|
||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL");
|
||||
|
||||
// If we are searching for a particular keyring's ids, add where
|
||||
if (match == KEY_RING_USER_IDS) {
|
||||
qb.appendWhere(Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = ");
|
||||
// TODO remove with the thing above
|
||||
qb.appendWhere(" AND ");
|
||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = ");
|
||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(sortOrder)) {
|
||||
sortOrder = Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " ASC"
|
||||
+ "," + Tables.USER_IDS + "." + UserIds.RANK + " ASC";
|
||||
sortOrder = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " ASC"
|
||||
+ "," + Tables.USER_PACKETS + "." + UserPackets.RANK + " ASC";
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -497,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);
|
||||
@@ -515,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);
|
||||
@@ -533,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);
|
||||
@@ -542,20 +552,24 @@ public class KeychainProvider extends ContentProvider {
|
||||
projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION);
|
||||
projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER);
|
||||
projectionMap.put(Certs.DATA, Tables.CERTS + "." + Certs.DATA);
|
||||
projectionMap.put(Certs.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
|
||||
projectionMap.put(Certs.SIGNER_UID, "signer." + UserIds.USER_ID + " AS " + Certs.SIGNER_UID);
|
||||
projectionMap.put(Certs.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID);
|
||||
projectionMap.put(Certs.SIGNER_UID, "signer." + UserPackets.USER_ID + " AS " + Certs.SIGNER_UID);
|
||||
qb.setProjectionMap(projectionMap);
|
||||
|
||||
qb.setTables(Tables.CERTS
|
||||
+ " JOIN " + Tables.USER_IDS + " ON ("
|
||||
+ " JOIN " + Tables.USER_PACKETS + " ON ("
|
||||
+ Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = "
|
||||
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||
+ " AND "
|
||||
+ Tables.CERTS + "." + Certs.RANK + " = "
|
||||
+ Tables.USER_IDS + "." + UserIds.RANK
|
||||
+ ") LEFT JOIN " + Tables.USER_IDS + " AS signer ON ("
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.RANK
|
||||
// for now, we only return user ids here, so TYPE must be NULL
|
||||
// TODO at some point, we should lift this restriction
|
||||
+ " AND "
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL"
|
||||
+ ") LEFT JOIN " + Tables.USER_PACKETS + " AS signer ON ("
|
||||
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = "
|
||||
+ "signer." + UserIds.MASTER_KEY_ID
|
||||
+ "signer." + UserPackets.MASTER_KEY_ID
|
||||
+ " AND "
|
||||
+ "signer." + Keys.RANK + " = 0"
|
||||
+ ")");
|
||||
@@ -662,8 +676,18 @@ public class KeychainProvider extends ContentProvider {
|
||||
break;
|
||||
|
||||
case KEY_RING_USER_IDS:
|
||||
db.insertOrThrow(Tables.USER_IDS, null, values);
|
||||
keyId = values.getAsLong(UserIds.MASTER_KEY_ID);
|
||||
// iff TYPE is null, user_id MUST be null as well
|
||||
if ( ! (values.get(UserPacketsColumns.TYPE) == null
|
||||
? (values.get(UserPacketsColumns.USER_ID) != null && values.get(UserPacketsColumns.ATTRIBUTE_DATA) == null)
|
||||
: (values.get(UserPacketsColumns.ATTRIBUTE_DATA) != null && values.get(UserPacketsColumns.USER_ID) == null)
|
||||
)) {
|
||||
throw new AssertionError("Incorrect type for user packet! This is a bug!");
|
||||
}
|
||||
if (values.get(UserPacketsColumns.RANK) == 0 && values.get(UserPacketsColumns.USER_ID) == null) {
|
||||
throw new AssertionError("Rank 0 user packet must be a user id!");
|
||||
}
|
||||
db.insertOrThrow(Tables.USER_PACKETS, null, values);
|
||||
keyId = values.getAsLong(UserPackets.MASTER_KEY_ID);
|
||||
break;
|
||||
|
||||
case KEY_RING_CERTS:
|
||||
|
||||
@@ -31,6 +31,8 @@ import android.support.v4.util.LongSparseArray;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
@@ -53,7 +55,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||
import org.sufficientlysecure.keychain.remote.AppSettings;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
@@ -169,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) {
|
||||
@@ -220,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);
|
||||
@@ -349,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
|
||||
@@ -439,18 +440,18 @@ 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<>();
|
||||
|
||||
if (trustedKeys.size() == 0) {
|
||||
log(LogType.MSG_IP_UID_CLASSIFYING_ZERO);
|
||||
} else {
|
||||
log(LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size());
|
||||
}
|
||||
mIndent += 1;
|
||||
List<UserIdItem> uids = new ArrayList<UserIdItem>();
|
||||
for (byte[] rawUserId : new IterableIterator<byte[]>(
|
||||
masterKey.getUnorderedRawUserIds().iterator())) {
|
||||
for (byte[] rawUserId : masterKey.getUnorderedRawUserIds()) {
|
||||
String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId);
|
||||
|
||||
UserIdItem item = new UserIdItem();
|
||||
UserPacketItem item = new UserPacketItem();
|
||||
uids.add(item);
|
||||
item.userId = userId;
|
||||
|
||||
@@ -459,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
|
||||
@@ -533,6 +534,105 @@ public class ProviderHelper {
|
||||
}
|
||||
mIndent -= 1;
|
||||
|
||||
ArrayList<WrappedUserAttribute> userAttributes = masterKey.getUnorderedUserAttributes();
|
||||
// Don't spam the log if there aren't even any attributes
|
||||
if ( ! userAttributes.isEmpty()) {
|
||||
log(LogType.MSG_IP_UAT_CLASSIFYING);
|
||||
}
|
||||
|
||||
mIndent += 1;
|
||||
for (WrappedUserAttribute userAttribute : userAttributes) {
|
||||
|
||||
UserPacketItem item = new UserPacketItem();
|
||||
uids.add(item);
|
||||
item.type = userAttribute.getType();
|
||||
item.attributeData = userAttribute.getEncoded();
|
||||
|
||||
int unknownCerts = 0;
|
||||
|
||||
switch (item.type) {
|
||||
case WrappedUserAttribute.UAT_IMAGE:
|
||||
log(LogType.MSG_IP_UAT_PROCESSING_IMAGE);
|
||||
break;
|
||||
default:
|
||||
log(LogType.MSG_IP_UAT_PROCESSING_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
mIndent += 1;
|
||||
// look through signatures for this specific key
|
||||
for (WrappedSignature cert : new IterableIterator<>(
|
||||
masterKey.getSignaturesForUserAttribute(userAttribute))) {
|
||||
long certId = cert.getKeyId();
|
||||
// self signature
|
||||
if (certId == masterKeyId) {
|
||||
|
||||
// NOTE self-certificates are already verified during canonicalization,
|
||||
// AND we know there is at most one cert plus at most one revocation
|
||||
if (!cert.isRevocation()) {
|
||||
item.selfCert = cert;
|
||||
} else {
|
||||
item.isRevoked = true;
|
||||
log(LogType.MSG_IP_UAT_REVOKED);
|
||||
}
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// do we have a trusted key for this?
|
||||
if (trustedKeys.indexOfKey(certId) < 0) {
|
||||
unknownCerts += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// verify signatures from known private keys
|
||||
CanonicalizedPublicKey trustedKey = trustedKeys.get(certId);
|
||||
|
||||
try {
|
||||
cert.init(trustedKey);
|
||||
// if it doesn't certify, leave a note and skip
|
||||
if ( ! cert.verifySignature(masterKey, userAttribute)) {
|
||||
log(LogType.MSG_IP_UAT_CERT_BAD);
|
||||
continue;
|
||||
}
|
||||
|
||||
log(cert.isRevocation()
|
||||
? LogType.MSG_IP_UAT_CERT_GOOD_REVOKE
|
||||
: LogType.MSG_IP_UAT_CERT_GOOD,
|
||||
KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId())
|
||||
);
|
||||
|
||||
// check if there is a previous certificate
|
||||
WrappedSignature prev = item.trustedCerts.get(cert.getKeyId());
|
||||
if (prev != null) {
|
||||
// if it's newer, skip this one
|
||||
if (prev.getCreationTime().after(cert.getCreationTime())) {
|
||||
log(LogType.MSG_IP_UAT_CERT_OLD);
|
||||
continue;
|
||||
}
|
||||
// if the previous one was a non-revokable certification, no need to look further
|
||||
if (!prev.isRevocation() && !prev.isRevokable()) {
|
||||
log(LogType.MSG_IP_UAT_CERT_NONREVOKE);
|
||||
continue;
|
||||
}
|
||||
log(LogType.MSG_IP_UAT_CERT_NEW);
|
||||
}
|
||||
item.trustedCerts.put(cert.getKeyId(), cert);
|
||||
|
||||
} catch (PgpGeneralException e) {
|
||||
log(LogType.MSG_IP_UAT_CERT_ERROR,
|
||||
KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (unknownCerts > 0) {
|
||||
log(LogType.MSG_IP_UAT_CERTS_UNKNOWN, unknownCerts);
|
||||
}
|
||||
mIndent -= 1;
|
||||
|
||||
}
|
||||
mIndent -= 1;
|
||||
|
||||
progress.setProgress(LogType.MSG_IP_UID_REORDER.getMsgId(), 65, 100);
|
||||
log(LogType.MSG_IP_UID_REORDER);
|
||||
// primary before regular before revoked (see UserIdItem.compareTo)
|
||||
@@ -540,7 +640,7 @@ public class ProviderHelper {
|
||||
Collections.sort(uids);
|
||||
// iterate and put into db
|
||||
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
|
||||
UserIdItem item = uids.get(userIdRank);
|
||||
UserPacketItem item = uids.get(userIdRank);
|
||||
operations.add(buildUserIdOperations(masterKeyId, item, userIdRank));
|
||||
if (item.selfCert != null) {
|
||||
// TODO get rid of "self verified" status? this cannot even happen anymore!
|
||||
@@ -605,23 +705,31 @@ public class ProviderHelper {
|
||||
|
||||
}
|
||||
|
||||
private static class UserIdItem implements Comparable<UserIdItem> {
|
||||
private static class UserPacketItem implements Comparable<UserPacketItem> {
|
||||
Integer type;
|
||||
String userId;
|
||||
byte[] attributeData;
|
||||
boolean isPrimary = false;
|
||||
boolean isRevoked = false;
|
||||
WrappedSignature selfCert;
|
||||
LongSparseArray<WrappedSignature> trustedCerts = new LongSparseArray<WrappedSignature>();
|
||||
LongSparseArray<WrappedSignature> trustedCerts = new LongSparseArray<>();
|
||||
|
||||
@Override
|
||||
public int compareTo(UserIdItem o) {
|
||||
// if one key is primary but the other isn't, the primary one always comes first
|
||||
if (isPrimary != o.isPrimary) {
|
||||
return isPrimary ? -1 : 1;
|
||||
}
|
||||
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
|
||||
if (type != o.type) {
|
||||
return type == null ? -1 : 1;
|
||||
}
|
||||
// if one key is primary but the other isn't, the primary one always comes first
|
||||
if (isPrimary != o.isPrimary) {
|
||||
return isPrimary ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -967,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;
|
||||
|
||||
@@ -1029,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;
|
||||
|
||||
@@ -1112,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 {
|
||||
@@ -1234,15 +1342,17 @@ public class ProviderHelper {
|
||||
* Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing
|
||||
*/
|
||||
private ContentProviderOperation
|
||||
buildUserIdOperations(long masterKeyId, UserIdItem item, int rank) {
|
||||
buildUserIdOperations(long masterKeyId, UserPacketItem item, int rank) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(UserIds.MASTER_KEY_ID, masterKeyId);
|
||||
values.put(UserIds.USER_ID, item.userId);
|
||||
values.put(UserIds.IS_PRIMARY, item.isPrimary);
|
||||
values.put(UserIds.IS_REVOKED, item.isRevoked);
|
||||
values.put(UserIds.RANK, rank);
|
||||
values.put(UserPackets.MASTER_KEY_ID, masterKeyId);
|
||||
values.put(UserPackets.TYPE, item.type);
|
||||
values.put(UserPackets.USER_ID, item.userId);
|
||||
values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData);
|
||||
values.put(UserPackets.IS_PRIMARY, item.isPrimary);
|
||||
values.put(UserPackets.IS_REVOKED, item.isRevoked);
|
||||
values.put(UserPackets.RANK, rank);
|
||||
|
||||
Uri uri = UserIds.buildUserIdsUri(masterKeyId);
|
||||
Uri uri = UserPackets.buildUserIdsUri(masterKeyId);
|
||||
|
||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
||||
}
|
||||
@@ -1270,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);
|
||||
@@ -1375,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 {
|
||||
@@ -1395,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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -20,14 +20,13 @@ 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;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.ActionBarHelper;
|
||||
import org.sufficientlysecure.keychain.ui.BaseActivity;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
@@ -35,7 +34,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp
|
||||
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class AccountSettingsActivity extends ActionBarActivity {
|
||||
public class AccountSettingsActivity extends BaseActivity {
|
||||
private Uri mAccountUri;
|
||||
|
||||
private AccountSettingsFragment mAccountSettingsFragment;
|
||||
@@ -45,17 +44,20 @@ public class AccountSettingsActivity extends ActionBarActivity {
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
setContentView(R.layout.api_account_settings_activity);
|
||||
|
||||
mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
|
||||
R.id.api_account_settings_fragment);
|
||||
@@ -72,6 +74,11 @@ public class AccountSettingsActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.api_account_settings_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
@@ -125,9 +132,4 @@ public class AccountSettingsActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
save();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -33,9 +31,10 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.remote.AppSettings;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.ui.BaseActivity;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class AppSettingsActivity extends ActionBarActivity {
|
||||
public class AppSettingsActivity extends BaseActivity {
|
||||
private Uri mAppUri;
|
||||
|
||||
private AppSettingsFragment mSettingsFragment;
|
||||
@@ -49,12 +48,11 @@ public class AppSettingsActivity extends ActionBarActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// let the actionbar look like Android's contact app
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setIcon(android.R.color.transparent);
|
||||
actionBar.setHomeButtonEnabled(true);
|
||||
// ActionBar actionBar = getSupportActionBar();
|
||||
// actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
// actionBar.setIcon(android.R.color.transparent);
|
||||
// actionBar.setHomeButtonEnabled(true);
|
||||
|
||||
setContentView(R.layout.api_app_settings_activity);
|
||||
|
||||
mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
|
||||
R.id.api_app_settings_fragment);
|
||||
@@ -71,6 +69,11 @@ public class AppSettingsActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.api_app_settings_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
@@ -21,16 +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);
|
||||
|
||||
public void init(Bundle savedInstanceState) {
|
||||
super.init(savedInstanceState);
|
||||
setContentView(R.layout.api_apps_list_activity);
|
||||
|
||||
activateDrawerNavigation(savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// protected void initLayout() {
|
||||
// setContentView(R.layout.api_apps_list_activity);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -39,14 +38,14 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RemoteServiceActivity extends ActionBarActivity {
|
||||
public class RemoteServiceActivity extends BaseActivity {
|
||||
|
||||
public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER";
|
||||
public static final String ACTION_CREATE_ACCOUNT = Constants.INTENT_PREFIX
|
||||
@@ -96,235 +95,250 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
||||
handleActions(getIntent(), savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
// done in handleActions()
|
||||
}
|
||||
|
||||
protected void handleActions(Intent intent, Bundle savedInstanceState) {
|
||||
|
||||
String action = intent.getAction();
|
||||
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);
|
||||
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());
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if (ACTION_CREATE_ACCOUNT.equals(action)) {
|
||||
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
|
||||
final String accName = extras.getString(EXTRA_ACC_NAME);
|
||||
|
||||
setContentView(R.layout.api_remote_create_account);
|
||||
|
||||
mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
|
||||
R.id.api_account_settings_fragment);
|
||||
|
||||
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;
|
||||
|
||||
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());
|
||||
} else {
|
||||
mProviderHelper.insertApiAccount(
|
||||
KeychainContract.ApiAccounts.buildBaseUri(packageName),
|
||||
mAccSettingsFragment.getAccSettings());
|
||||
}
|
||||
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_close_white_24dp,
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Disallow
|
||||
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();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
} 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);
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
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();
|
||||
|
||||
mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
|
||||
R.id.api_account_settings_fragment);
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
||||
// 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());
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.api_remote_select_pub_keys);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Create an instance of the fragment
|
||||
mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds);
|
||||
setContentView(R.layout.api_remote_select_pub_keys);
|
||||
initToolbar();
|
||||
|
||||
// Add the fragment to the 'fragment_container' FrameLayout
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit();
|
||||
}
|
||||
} else if (ACTION_ERROR_MESSAGE.equals(action)) {
|
||||
String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE);
|
||||
// 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());
|
||||
|
||||
Spannable redErrorMessage = new SpannableString(errorMessage);
|
||||
redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
// Inflate a "Done" custom action bar view
|
||||
ActionBarHelper.setOneButtonView(getSupportActionBar(),
|
||||
R.string.btn_okay, R.drawable.ic_action_done,
|
||||
new View.OnClickListener() {
|
||||
// set text on view
|
||||
TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text);
|
||||
textView.setText(ssb, TextView.BufferType.SPANNABLE);
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
|
||||
RemoteServiceActivity.this.finish();
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.api_remote_error_message);
|
||||
// Create an instance of the fragment
|
||||
mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds);
|
||||
|
||||
// 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();
|
||||
// Add the fragment to the 'fragment_container' FrameLayout
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
setContentView(R.layout.api_remote_error_message);
|
||||
initToolbar();
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -30,9 +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.PromoteKeyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
@@ -90,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";
|
||||
|
||||
@@ -160,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";
|
||||
|
||||
@@ -223,301 +231,326 @@ 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);
|
||||
|
||||
// Operation
|
||||
CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled);
|
||||
CertifyResult result = op.certify(parcel, keyServerUri);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_CONSOLIDATE.equals(action)) {
|
||||
|
||||
// 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);
|
||||
|
||||
} else if (ACTION_DECRYPT_METADATA.equals(action)) {
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
|
||||
/* Operation */
|
||||
|
||||
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);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
/* Operation */
|
||||
|
||||
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);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
outStream.close();
|
||||
|
||||
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
|
||||
|
||||
/* Output */
|
||||
|
||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_DELETE.equals(action)) {
|
||||
|
||||
// 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);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_EDIT_KEYRING.equals(action)) {
|
||||
|
||||
// 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);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
||||
|
||||
// Input
|
||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||
String outputFile = data.getString(EXPORT_FILENAME);
|
||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||
|
||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// 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);
|
||||
|
||||
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
|
||||
|
||||
try {
|
||||
switch (action) {
|
||||
case ACTION_CERTIFY_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();
|
||||
}
|
||||
CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL);
|
||||
String keyServerUri = data.getString(UPLOAD_KEY_SERVER);
|
||||
|
||||
// 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();
|
||||
CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled);
|
||||
CertifyResult result = op.certify(parcel, keyServerUri);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_CONSOLIDATE: {
|
||||
|
||||
} else if (ACTION_SIGN_ENCRYPT.equals(action)) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
try {
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_DECRYPT_METADATA:
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
Bundle resultData = new Bundle();
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID);
|
||||
String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE);
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
|
||||
byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH);
|
||||
Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP);
|
||||
/* Operation */
|
||||
|
||||
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
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
|
||||
// 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.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||
.setCompressionId(compressionId)
|
||||
.setSymmetricEncryptionAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
|
||||
.setEncryptionMasterKeyIds(encryptionKeyIds)
|
||||
.setSymmetricPassphrase(symmetricPassphrase)
|
||||
.setOriginalFilename(originalFilename);
|
||||
builder.setAllowSymmetricDecryption(true)
|
||||
.setPassphrase(passphrase)
|
||||
.setDecryptMetadataOnly(true)
|
||||
.setNfcState(nfcDecryptedSessionKey);
|
||||
|
||||
try {
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
// Find the appropriate subkey to sign with
|
||||
CachedPublicKeyRing signingRing =
|
||||
new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId);
|
||||
long sigSubKeyId = signingRing.getSecretSignId();
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
break;
|
||||
case ACTION_DECRYPT_VERIFY:
|
||||
|
||||
} catch (PgpKeyNotFoundException e) {
|
||||
// encrypt-only
|
||||
// TODO Just silently drop the requested signature? Shouldn't we throw here?
|
||||
}
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
// this assumes that the bytes are cleartext (valid for current implementation!)
|
||||
if (source == IO_BYTES) {
|
||||
builder.setCleartextSignature(true);
|
||||
}
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
SignEncryptResult result = builder.build().execute();
|
||||
resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result);
|
||||
/* Operation */
|
||||
|
||||
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);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
outStream.close();
|
||||
|
||||
/* Output */
|
||||
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
|
||||
|
||||
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||
/* Output */
|
||||
|
||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
break;
|
||||
case ACTION_DELETE: {
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
// 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);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_EDIT_KEYRING: {
|
||||
|
||||
} else if (ACTION_UPLOAD_KEYRING.equals(action)) {
|
||||
// Input
|
||||
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
|
||||
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
|
||||
|
||||
try {
|
||||
// Operation
|
||||
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
|
||||
EditKeyResult result = op.execute(saveParcel, passphrase);
|
||||
|
||||
/* Input */
|
||||
String keyServer = data.getString(UPLOAD_KEY_SERVER);
|
||||
// and dataUri!
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
/* Operation */
|
||||
HkpKeyserver server = new HkpKeyserver(keyServer);
|
||||
break;
|
||||
}
|
||||
case ACTION_PROMOTE_KEYRING: {
|
||||
|
||||
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
|
||||
// Input
|
||||
long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// Operation
|
||||
PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled);
|
||||
PromoteKeyResult result = op.execute(keyRingId);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_EXPORT_KEYRING: {
|
||||
|
||||
// Input
|
||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||
String outputFile = data.getString(EXPORT_FILENAME);
|
||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||
|
||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// 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:
|
||||
|
||||
try {
|
||||
importExportOperation.uploadKeyRingToServer(server, keyring);
|
||||
} catch (Keyserver.AddKeyException e) {
|
||||
throw new PgpGeneralException("Unable to export key to selected server");
|
||||
|
||||
// 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<>(this, "key_import.pcl");
|
||||
IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
|
||||
entries = it;
|
||||
numEntries = it.getSize();
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
break;
|
||||
case ACTION_SIGN_ENCRYPT:
|
||||
|
||||
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);
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
SignEncryptResult result = builder.build().execute();
|
||||
resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result);
|
||||
|
||||
outStream.close();
|
||||
|
||||
/* Output */
|
||||
|
||||
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||
|
||||
}
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
break;
|
||||
case ACTION_UPLOAD_KEYRING:
|
||||
|
||||
try {
|
||||
|
||||
/* Input */
|
||||
String keyServer = data.getString(UPLOAD_KEY_SERVER);
|
||||
// and dataUri!
|
||||
|
||||
/* Operation */
|
||||
HkpKeyserver server = new HkpKeyserver(keyServer);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.service;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -49,6 +50,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
public ChangeUnlockParcel mNewUnlock;
|
||||
|
||||
public ArrayList<String> mAddUserIds;
|
||||
public ArrayList<WrappedUserAttribute> mAddUserAttribute;
|
||||
public ArrayList<SubkeyAdd> mAddSubKeys;
|
||||
|
||||
public ArrayList<SubkeyChange> mChangeSubKeys;
|
||||
@@ -56,7 +58,6 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
public ArrayList<String> mRevokeUserIds;
|
||||
public ArrayList<Long> mRevokeSubKeys;
|
||||
public ArrayList<Long> mStripSubKeys;
|
||||
|
||||
public SaveKeyringParcel() {
|
||||
reset();
|
||||
@@ -70,13 +71,30 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
public void reset() {
|
||||
mNewUnlock = null;
|
||||
mAddUserIds = new ArrayList<String>();
|
||||
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,
|
||||
@@ -109,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;
|
||||
}
|
||||
@@ -162,6 +207,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
mNewUnlock = source.readParcelable(getClass().getClassLoader());
|
||||
|
||||
mAddUserIds = source.createStringArrayList();
|
||||
mAddUserAttribute = (ArrayList<WrappedUserAttribute>) source.readSerializable();
|
||||
mAddSubKeys = (ArrayList<SubkeyAdd>) source.readSerializable();
|
||||
|
||||
mChangeSubKeys = (ArrayList<SubkeyChange>) source.readSerializable();
|
||||
@@ -169,7 +215,6 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
mRevokeUserIds = source.createStringArrayList();
|
||||
mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
|
||||
mStripSubKeys = (ArrayList<Long>) source.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +229,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
destination.writeParcelable(mNewUnlock, 0);
|
||||
|
||||
destination.writeStringList(mAddUserIds);
|
||||
destination.writeSerializable(mAddUserAttribute);
|
||||
destination.writeSerializable(mAddSubKeys);
|
||||
|
||||
destination.writeSerializable(mChangeSubKeys);
|
||||
@@ -191,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>() {
|
||||
@@ -214,12 +259,12 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
String out = "mMasterKeyId: " + mMasterKeyId + "\n";
|
||||
out += "mNewUnlock: " + mNewUnlock + "\n";
|
||||
out += "mAddUserIds: " + mAddUserIds + "\n";
|
||||
out += "mAddUserAttribute: " + mAddUserAttribute + "\n";
|
||||
out += "mAddSubKeys: " + mAddSubKeys + "\n";
|
||||
out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
|
||||
out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
|
||||
out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
|
||||
out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n";
|
||||
out += "mStripSubKeys: " + mStripSubKeys;
|
||||
out += "mRevokeSubKeys: " + mRevokeSubKeys;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Setups Toolbar
|
||||
*/
|
||||
public abstract class BaseActivity extends ActionBarActivity {
|
||||
protected Toolbar mToolbar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initLayout();
|
||||
initToolbar();
|
||||
}
|
||||
|
||||
protected abstract void initLayout();
|
||||
|
||||
protected void initToolbar() {
|
||||
mToolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
if (mToolbar != null) {
|
||||
setSupportActionBar(mToolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -18,24 +18,19 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
/**
|
||||
* Signs the specified public key with the specified secret master key
|
||||
*/
|
||||
public class CertifyKeyActivity extends ActionBarActivity {
|
||||
public class CertifyKeyActivity extends BaseActivity {
|
||||
|
||||
public static final String EXTRA_RESULT = "operation_result";
|
||||
public static final String EXTRA_KEY_IDS = "extra_key_ids";
|
||||
public static final String EXTRA_CERTIFY_KEY_ID = "certify_key_id";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.certify_key_activity);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||
@@ -82,11 +82,11 @@ public class CertifyKeyFragment extends LoaderFragment
|
||||
private long mSignMasterKeyId = Constants.key.none;
|
||||
|
||||
public static final String[] USER_IDS_PROJECTION = new String[]{
|
||||
UserIds._ID,
|
||||
UserIds.MASTER_KEY_ID,
|
||||
UserIds.USER_ID,
|
||||
UserIds.IS_PRIMARY,
|
||||
UserIds.IS_REVOKED
|
||||
UserPackets._ID,
|
||||
UserPackets.MASTER_KEY_ID,
|
||||
UserPackets.USER_ID,
|
||||
UserPackets.IS_PRIMARY,
|
||||
UserPackets.IS_REVOKED
|
||||
};
|
||||
private static final int INDEX_MASTER_KEY_ID = 1;
|
||||
private static final int INDEX_USER_ID = 2;
|
||||
@@ -182,7 +182,7 @@ public class CertifyKeyFragment extends LoaderFragment
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
Uri uri = UserIds.buildUserIdsUri();
|
||||
Uri uri = UserPackets.buildUserIdsUri();
|
||||
|
||||
String selection, ids[];
|
||||
{
|
||||
@@ -196,15 +196,15 @@ public class CertifyKeyFragment extends LoaderFragment
|
||||
}
|
||||
}
|
||||
// put together selection string
|
||||
selection = UserIds.IS_REVOKED + " = 0" + " AND "
|
||||
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
|
||||
selection = UserPackets.IS_REVOKED + " = 0" + " AND "
|
||||
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||
+ " IN (" + placeholders + ")";
|
||||
}
|
||||
|
||||
return new CursorLoader(getActivity(), uri,
|
||||
USER_IDS_PROJECTION, selection, ids,
|
||||
Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " ASC"
|
||||
+ ", " + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC"
|
||||
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " ASC"
|
||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -20,11 +20,10 @@ 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;
|
||||
|
||||
public class CreateKeyActivity extends ActionBarActivity {
|
||||
public class CreateKeyActivity extends BaseActivity {
|
||||
|
||||
public static final String EXTRA_NAME = "name";
|
||||
public static final String EXTRA_EMAIL = "email";
|
||||
@@ -37,8 +36,6 @@ public class CreateKeyActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.create_key_activity);
|
||||
|
||||
// pass extras into fragment
|
||||
CreateKeyInputFragment frag =
|
||||
CreateKeyInputFragment.newInstance(
|
||||
@@ -48,6 +45,11 @@ public class CreateKeyActivity extends ActionBarActivity {
|
||||
loadFragment(null, frag, FRAG_ACTION_START);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.create_key_activity);
|
||||
}
|
||||
|
||||
public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) {
|
||||
// However, if we're being restored from a previous state,
|
||||
// then we don't need to do anything and should return or else
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
|
||||
@@ -40,8 +40,6 @@ public class DecryptActivity extends DrawerActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.decrypt_activity);
|
||||
|
||||
activateDrawerNavigation(savedInstanceState);
|
||||
|
||||
View actionFile = findViewById(R.id.decrypt_files);
|
||||
@@ -66,6 +64,11 @@ public class DecryptActivity extends DrawerActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.decrypt_activity);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.HONEYCOMB)
|
||||
@Override
|
||||
protected void onResume() {
|
||||
|
||||
@@ -20,14 +20,13 @@ 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;
|
||||
import org.sufficientlysecure.keychain.api.OpenKeychainIntents;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class DecryptFilesActivity extends ActionBarActivity {
|
||||
public class DecryptFilesActivity extends BaseActivity {
|
||||
|
||||
/* Intents */
|
||||
public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA;
|
||||
@@ -41,12 +40,15 @@ public class DecryptFilesActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.decrypt_files_activity);
|
||||
|
||||
// Handle intent actions
|
||||
handleActions(savedInstanceState, getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.decrypt_files_activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all actions with this intent
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
@@ -35,7 +34,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class DecryptTextActivity extends ActionBarActivity {
|
||||
public class DecryptTextActivity extends BaseActivity {
|
||||
|
||||
/* Intents */
|
||||
public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT;
|
||||
@@ -50,12 +49,15 @@ public class DecryptTextActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.decrypt_text_activity);
|
||||
|
||||
// Handle intent actions
|
||||
handleActions(savedInstanceState, getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.decrypt_text_activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail
|
||||
*/
|
||||
|
||||
@@ -111,7 +111,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"
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v4.widget.FixedDrawerLayout;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -42,7 +41,7 @@ import android.widget.TextView;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
public class DrawerActivity extends ActionBarActivity {
|
||||
public abstract class DrawerActivity extends BaseActivity {
|
||||
private FixedDrawerLayout mDrawerLayout;
|
||||
private ListView mDrawerList;
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
@@ -179,7 +178,7 @@ public class DrawerActivity extends ActionBarActivity {
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ID_PREFERENCE: {
|
||||
Intent intent = new Intent(this, PreferencesActivity.class);
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ 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;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class EditKeyActivity extends ActionBarActivity {
|
||||
public class EditKeyActivity extends BaseActivity {
|
||||
|
||||
public static final String EXTRA_SAVE_KEYRING_PARCEL = "save_keyring_parcel";
|
||||
|
||||
@@ -36,8 +35,6 @@ public class EditKeyActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.edit_key_activity);
|
||||
|
||||
Uri dataUri = getIntent().getData();
|
||||
SaveKeyringParcel saveKeyringParcel = getIntent().getParcelableExtra(EXTRA_SAVE_KEYRING_PARCEL);
|
||||
if (dataUri == null && saveKeyringParcel == null) {
|
||||
@@ -49,6 +46,11 @@ public class EditKeyActivity extends ActionBarActivity {
|
||||
loadFragment(savedInstanceState, dataUri, saveKeyringParcel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.edit_key_activity);
|
||||
}
|
||||
|
||||
private void loadFragment(Bundle savedInstanceState, Uri dataUri, SaveKeyringParcel saveKeyringParcel) {
|
||||
// However, if we're being restored from a previous state,
|
||||
// then we don't need to do anything and should return or else
|
||||
|
||||
@@ -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;
|
||||
@@ -47,6 +46,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
@@ -54,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;
|
||||
@@ -64,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;
|
||||
|
||||
@@ -146,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) {
|
||||
@@ -160,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);
|
||||
@@ -229,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;
|
||||
}
|
||||
@@ -334,7 +326,7 @@ public class EditKeyFragment extends LoaderFragment implements
|
||||
|
||||
switch (id) {
|
||||
case LOADER_ID_USER_IDS: {
|
||||
Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri);
|
||||
Uri baseUri = UserPackets.buildUserIdsUri(mDataUri);
|
||||
return new CursorLoader(getActivity(), baseUri,
|
||||
UserIdsAdapter.USER_IDS_PROJECTION, null, null, null);
|
||||
}
|
||||
@@ -394,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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -477,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();
|
||||
|
||||
@@ -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 NavDrawerActivity {
|
||||
|
||||
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
|
||||
public static final int REQUEST_CODE_NFC = 0x00008002;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
@@ -309,15 +309,13 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.encrypt_files_activity);
|
||||
|
||||
// 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
|
||||
@@ -327,6 +325,11 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
|
||||
mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void initLayout() {
|
||||
// setContentView(R.layout.encrypt_files_activity);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.encrypt_file_activity, menu);
|
||||
@@ -379,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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -288,15 +289,13 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.encrypt_text_activity);
|
||||
|
||||
// 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
|
||||
@@ -304,6 +303,11 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
|
||||
updateModeFragment();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void initLayout() {
|
||||
// setContentView(R.layout.encrypt_text_activity);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.encrypt_text_activity, menu);
|
||||
|
||||
@@ -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;
|
||||
@@ -29,7 +28,7 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class FirstTimeActivity extends ActionBarActivity {
|
||||
public class FirstTimeActivity extends BaseActivity {
|
||||
|
||||
View mCreateKey;
|
||||
View mImportKey;
|
||||
@@ -43,8 +42,6 @@ public class FirstTimeActivity extends ActionBarActivity {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.first_time_activity);
|
||||
|
||||
mCreateKey = findViewById(R.id.first_time_create_key);
|
||||
mImportKey = findViewById(R.id.first_time_import_key);
|
||||
mSkipSetup = findViewById(R.id.first_time_cancel);
|
||||
@@ -72,7 +69,11 @@ public class FirstTimeActivity extends ActionBarActivity {
|
||||
startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.first_time_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,7 +97,7 @@ public class FirstTimeActivity extends ActionBarActivity {
|
||||
if (srcData != null) {
|
||||
intent.putExtras(srcData);
|
||||
}
|
||||
startActivityForResult(intent, 0);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -105,4 +106,5 @@ public class FirstTimeActivity extends ActionBarActivity {
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ package org.sufficientlysecure.keychain.ui;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.View;
|
||||
|
||||
import com.astuetz.PagerSlidingTabStrip;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
|
||||
|
||||
public class HelpActivity extends ActionBarActivity {
|
||||
public class HelpActivity extends BaseActivity {
|
||||
public static final String EXTRA_SELECTED_TAB = "selected_tab";
|
||||
|
||||
public static final int TAB_START = 0;
|
||||
@@ -44,16 +44,16 @@ public class HelpActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||
actionBar.setHomeButtonEnabled(false);
|
||||
|
||||
setContentView(R.layout.help_activity);
|
||||
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||
SlidingTabLayout slidingTabLayout =
|
||||
(SlidingTabLayout) findViewById(R.id.sliding_tab_layout);
|
||||
PagerSlidingTabStrip slidingTabLayout =
|
||||
(PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout);
|
||||
|
||||
mTabsAdapter = new PagerTabStripAdapter(this);
|
||||
mViewPager.setAdapter(mTabsAdapter);
|
||||
@@ -98,4 +98,9 @@ public class HelpActivity extends ActionBarActivity {
|
||||
// switch to tab selected by extra
|
||||
mViewPager.setCurrentItem(selectedTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.help_activity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -51,7 +50,7 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ImportKeysActivity extends ActionBarActivity {
|
||||
public class ImportKeysActivity extends BaseActivity {
|
||||
public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY;
|
||||
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER;
|
||||
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT =
|
||||
@@ -90,8 +89,6 @@ public class ImportKeysActivity extends ActionBarActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.import_keys_activity);
|
||||
|
||||
mImportButton = findViewById(R.id.import_import);
|
||||
mImportButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
@@ -103,6 +100,11 @@ public class ImportKeysActivity extends ActionBarActivity {
|
||||
handleActions(savedInstanceState, getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.import_keys_activity);
|
||||
}
|
||||
|
||||
protected void handleActions(Bundle savedInstanceState, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Bundle extras = intent.getExtras();
|
||||
@@ -119,95 +121,102 @@ public class ImportKeysActivity extends ActionBarActivity {
|
||||
action = ACTION_IMPORT_KEY;
|
||||
}
|
||||
|
||||
if (ACTION_IMPORT_KEY.equals(action)) {
|
||||
switch (action) {
|
||||
case ACTION_IMPORT_KEY:
|
||||
/* Keychain's own Actions */
|
||||
startFileFragment(savedInstanceState);
|
||||
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);
|
||||
}
|
||||
} 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)) {
|
||||
// action: directly load data
|
||||
startListFragment(savedInstanceState, importData, null, null);
|
||||
}
|
||||
break;
|
||||
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)) {
|
||||
// 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);
|
||||
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)) {
|
||||
// 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;
|
||||
}
|
||||
} else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) {
|
||||
// NOTE: this only displays the appropriate fragment, no actions are taken
|
||||
startFileFragment(savedInstanceState);
|
||||
break;
|
||||
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_FILE_AND_RETURN.equals(action)) {
|
||||
// NOTE: this only displays the appropriate fragment, no actions are taken
|
||||
startFileFragment(savedInstanceState);
|
||||
// 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 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_NFC:
|
||||
// NOTE: this only displays the appropriate fragment, no actions are taken
|
||||
startFileFragment(savedInstanceState);
|
||||
// TODO!!!!!
|
||||
|
||||
// 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;
|
||||
default:
|
||||
startCloudFragment(savedInstanceState, null, false);
|
||||
startListFragment(savedInstanceState, null, null, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +362,7 @@ public class ImportKeysActivity extends ActionBarActivity {
|
||||
// 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);
|
||||
@@ -385,7 +394,7 @@ public class ImportKeysActivity extends ActionBarActivity {
|
||||
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();
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -110,7 +110,7 @@ public class ImportKeysCloudFragment extends Fragment {
|
||||
mConfigButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent i = new Intent(mImportActivity, PreferencesActivity.class);
|
||||
Intent i = new Intent(mImportActivity, SettingsActivity.class);
|
||||
// GRR, for some reason I can’t set the Action or I get an incomprehensible
|
||||
// exception about “modern two-pane layouts”
|
||||
// i.setAction(PreferencesActivity.ACTION_PREFS_CLOUD);
|
||||
|
||||
@@ -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<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,15 +41,20 @@ 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);
|
||||
|
||||
@@ -63,12 +68,22 @@ public class KeyListActivity extends DrawerActivity {
|
||||
|
||||
mExportHelper = new ExportHelper(this);
|
||||
|
||||
setContentView(R.layout.key_list_activity);
|
||||
Intent data = getIntent();
|
||||
// If we got an EXTRA_RESULT in the intent, show the notification
|
||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
|
||||
result.createNotify(this).show();
|
||||
}
|
||||
|
||||
// now setup navigation drawer in DrawerActivity...
|
||||
activateDrawerNavigation(savedInstanceState);
|
||||
// activateDrawerNavigation(savedInstanceState);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void initLayout() {
|
||||
// setContentView(R.layout.key_list_activity);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
@@ -31,7 +30,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 +50,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 +57,9 @@ 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.DeleteResult;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
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 +68,10 @@ 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 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;
|
||||
|
||||
@@ -110,8 +95,6 @@ public class KeyListFragment extends LoaderFragment
|
||||
private String mQuery;
|
||||
private SearchView mSearchView;
|
||||
|
||||
boolean hideMenu = false;
|
||||
|
||||
/**
|
||||
* Load custom layout with StickyListView from library
|
||||
*/
|
||||
@@ -172,8 +155,8 @@ public class KeyListFragment extends LoaderFragment
|
||||
TextView title = (TextView) getActivity().findViewById(R.id.custom_actionbar_text);
|
||||
title.setText(R.string.swipe_to_update);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
hideMenu = true;
|
||||
activity.invalidateOptionsMenu();
|
||||
// hideMenu = true;
|
||||
// activity.invalidateOptionsMenu();
|
||||
}
|
||||
} else {
|
||||
bar.setTitle(getActivity().getTitle());
|
||||
@@ -184,8 +167,8 @@ public class KeyListFragment extends LoaderFragment
|
||||
bar.setDisplayShowCustomEnabled(false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
hideMenu = false;
|
||||
activity.invalidateOptionsMenu();
|
||||
// hideMenu = false;
|
||||
// activity.invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -470,10 +453,6 @@ public class KeyListFragment extends LoaderFragment
|
||||
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
hideMenu = true;
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
// disable swipe-to-refresh
|
||||
// mSwipeRefreshLayout.setIsLocked(true);
|
||||
@@ -485,22 +464,12 @@ public class KeyListFragment extends LoaderFragment
|
||||
mQuery = null;
|
||||
getLoaderManager().restartLoader(0, null, KeyListFragment.this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
hideMenu = false;
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
// enable swipe-to-refresh
|
||||
// mSwipeRefreshLayout.setIsLocked(false);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hideMenu) {
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
menu.getItem(i).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@@ -533,7 +502,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);
|
||||
|
||||
@@ -19,21 +19,18 @@
|
||||
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 ActionBarActivity {
|
||||
public class LogDisplayActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
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) {
|
||||
@@ -42,7 +39,10 @@ public class LogDisplayActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.log_display_activity);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.remote.ui.AppsListActivity;
|
||||
|
||||
import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer;
|
||||
|
||||
public abstract class NavDrawerActivity extends MaterialNavigationDrawer {
|
||||
|
||||
@Override
|
||||
public void init(Bundle savedInstanceState) {
|
||||
|
||||
// set the header image
|
||||
this.setDrawerHeaderImage(R.drawable.mat2);
|
||||
|
||||
// create sections
|
||||
this.addSection(newSection(getString(R.string.app_name), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment()));
|
||||
|
||||
this.addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class)));
|
||||
this.addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class)));
|
||||
this.addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class)));
|
||||
this.addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new Intent(this, AppsListActivity.class)));
|
||||
|
||||
// create bottom section
|
||||
this.addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class)));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -38,7 +35,7 @@ import java.util.Locale;
|
||||
* For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
|
||||
public class NfcActivity extends ActionBarActivity {
|
||||
public class NfcActivity extends BaseActivity {
|
||||
|
||||
// actions
|
||||
public static final String ACTION_SIGN_HASH = "sign_hash";
|
||||
@@ -82,8 +79,6 @@ public class NfcActivity extends ActionBarActivity {
|
||||
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
setContentView(R.layout.nfc_activity);
|
||||
|
||||
Intent intent = getIntent();
|
||||
Bundle data = intent.getExtras();
|
||||
String action = intent.getAction();
|
||||
@@ -93,36 +88,46 @@ public class NfcActivity extends ActionBarActivity {
|
||||
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);
|
||||
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());
|
||||
} 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 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());
|
||||
} 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.nfc_activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity,
|
||||
* disables NFC Foreground Dispatch
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -36,7 +35,7 @@ import java.nio.ByteBuffer;
|
||||
* For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
|
||||
public class NfcIntentActivity extends ActionBarActivity {
|
||||
public class NfcIntentActivity extends BaseActivity {
|
||||
|
||||
// special extra for OpenPgpService
|
||||
public static final String EXTRA_DATA = "data";
|
||||
@@ -54,8 +53,6 @@ public class NfcIntentActivity extends ActionBarActivity {
|
||||
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
setContentView(R.layout.nfc_activity);
|
||||
|
||||
Intent intent = getIntent();
|
||||
Bundle data = intent.getExtras();
|
||||
String action = intent.getAction();
|
||||
@@ -87,7 +84,11 @@ public class NfcIntentActivity extends ActionBarActivity {
|
||||
Log.e(Constants.TAG, "IOException!", e);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.nfc_activity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,11 @@ public class QrCodeScanActivity extends FragmentActivity {
|
||||
// scan using xzing's Barcode Scanner and return result parcel in OpenKeychain
|
||||
|
||||
returnResult = true;
|
||||
new IntentIntegrator(this).initiateScan();
|
||||
IntentIntegrator integrator = new IntentIntegrator(this);
|
||||
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
|
||||
.setPrompt(getString(R.string.import_qr_code_text))
|
||||
.setResultDisplayDuration(0)
|
||||
.initiateScan();
|
||||
} else if (ACTION_QR_CODE_API.equals(action)) {
|
||||
// scan using xzing's Barcode Scanner from outside OpenKeychain
|
||||
|
||||
@@ -168,7 +172,7 @@ public class QrCodeScanActivity extends FragmentActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! result.success()) {
|
||||
if (!result.success()) {
|
||||
// only return if no success...
|
||||
Intent data = new Intent();
|
||||
data.putExtras(returnData);
|
||||
@@ -199,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -36,7 +34,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
||||
|
||||
public class QrCodeViewActivity extends ActionBarActivity {
|
||||
public class QrCodeViewActivity extends BaseActivity {
|
||||
|
||||
private ImageView mFingerprintQrCode;
|
||||
|
||||
@@ -45,8 +43,7 @@ public class QrCodeViewActivity extends ActionBarActivity {
|
||||
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) {
|
||||
@@ -56,8 +53,6 @@ public class QrCodeViewActivity extends ActionBarActivity {
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.qr_code_activity);
|
||||
|
||||
Uri dataUri = getIntent().getData();
|
||||
if (dataUri == null) {
|
||||
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
|
||||
@@ -108,6 +103,11 @@ public class QrCodeViewActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.qr_code_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
@@ -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,13 +46,12 @@ 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;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public class SafeSlingerActivity extends ActionBarActivity {
|
||||
public class SafeSlingerActivity extends BaseActivity {
|
||||
|
||||
private static final int REQUEST_CODE_SAFE_SLINGER = 211;
|
||||
|
||||
@@ -69,51 +64,17 @@ public class SafeSlingerActivity extends ActionBarActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.safe_slinger_activity);
|
||||
|
||||
mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0);
|
||||
|
||||
// NOTE: there are two versions of this layout, for API >= 11 and one for < 11
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
NumberPicker picker = (NumberPicker) findViewById(R.id.safe_slinger_picker);
|
||||
picker.setMinValue(2);
|
||||
picker.setMaxValue(10);
|
||||
picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
|
||||
@Override
|
||||
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
||||
mSelectedNumber = newVal;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Spinner spinner = (Spinner) findViewById(R.id.safe_slinger_spinner);
|
||||
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
list.add("4");
|
||||
list.add("5");
|
||||
list.add("6");
|
||||
list.add("7");
|
||||
list.add("8");
|
||||
list.add("9");
|
||||
list.add("10");
|
||||
|
||||
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
|
||||
android.R.layout.simple_spinner_item, list);
|
||||
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(dataAdapter);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
mSelectedNumber = position + 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
NumberPicker picker = (NumberPicker) findViewById(R.id.safe_slinger_picker);
|
||||
picker.setMinValue(2);
|
||||
picker.setMaxValue(10);
|
||||
picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
|
||||
@Override
|
||||
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
||||
mSelectedNumber = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
ImageView buttonIcon = (ImageView) findViewById(R.id.safe_slinger_button_image);
|
||||
buttonIcon.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
|
||||
@@ -128,6 +89,11 @@ public class SafeSlingerActivity extends ActionBarActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.safe_slinger_activity);
|
||||
}
|
||||
|
||||
private void startExchange(long masterKeyId, int number) {
|
||||
// retrieve public key blob and start SafeSlinger
|
||||
Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(masterKeyId);
|
||||
@@ -221,7 +187,7 @@ public class SafeSlingerActivity extends ActionBarActivity {
|
||||
// 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
|
||||
@@ -249,7 +215,7 @@ public class SafeSlingerActivity extends ActionBarActivity {
|
||||
}
|
||||
|
||||
private static ArrayList<ParcelableKeyRing> getSlingedKeys(Bundle extras) {
|
||||
ArrayList<ParcelableKeyRing> list = new ArrayList<ParcelableKeyRing>();
|
||||
ArrayList<ParcelableKeyRing> list = new ArrayList<>();
|
||||
|
||||
if (extras != null) {
|
||||
byte[] d;
|
||||
|
||||
@@ -20,14 +20,12 @@ 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 ActionBarActivity {
|
||||
public class SelectPublicKeyActivity extends BaseActivity {
|
||||
|
||||
// Actions for internal use only:
|
||||
public static final String ACTION_SELECT_PUBLIC_KEYS = Constants.INTENT_PREFIX
|
||||
@@ -47,23 +45,19 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
|
||||
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();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.select_public_key_activity);
|
||||
});
|
||||
|
||||
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
||||
|
||||
@@ -101,6 +95,11 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.select_public_key_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
@@ -27,19 +27,22 @@ import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
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 org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public class PreferencesActivity extends PreferenceActivity {
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD";
|
||||
public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
|
||||
@@ -54,6 +57,8 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
sPreferences = Preferences.getPreferences(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setupToolbar();
|
||||
|
||||
String action = getIntent().getAction();
|
||||
|
||||
if (action != null && action.equals(ACTION_PREFS_CLOUD)) {
|
||||
@@ -64,9 +69,9 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
mKeyServerPreference
|
||||
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent intent = new Intent(PreferencesActivity.this,
|
||||
PreferencesKeyServerActivity.class);
|
||||
intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
Intent intent = new Intent(SettingsActivity.this,
|
||||
SettingsKeyServerActivity.class);
|
||||
intent.putExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
sPreferences.getKeyServers());
|
||||
startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF);
|
||||
return false;
|
||||
@@ -130,12 +135,33 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
initializeUseNumKeypadForYubikeyPin(
|
||||
(CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN));
|
||||
|
||||
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
// Load the legacy preferences headers
|
||||
addPreferencesFromResource(R.xml.preference_headers_legacy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack to get Toolbar in PreferenceActivity. See http://stackoverflow.com/a/26614696
|
||||
*/
|
||||
private void setupToolbar() {
|
||||
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
|
||||
LinearLayout content = (LinearLayout) root.getChildAt(0);
|
||||
LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar_activity, null);
|
||||
|
||||
root.removeAllViews();
|
||||
toolbarContainer.addView(content);
|
||||
root.addView(toolbarContainer);
|
||||
|
||||
Toolbar toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.title_preferences);
|
||||
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
//What to do on back clicked
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
@@ -144,7 +170,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
return;
|
||||
}
|
||||
String servers[] = data
|
||||
.getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
.getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
sPreferences.setKeyServers(servers);
|
||||
mKeyServerPreference.setSummary(keyserverSummary(this));
|
||||
break;
|
||||
@@ -185,8 +211,8 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent intent = new Intent(getActivity(),
|
||||
PreferencesKeyServerActivity.class);
|
||||
intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
SettingsKeyServerActivity.class);
|
||||
intent.putExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS,
|
||||
sPreferences.getKeyServers());
|
||||
startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF);
|
||||
return false;
|
||||
@@ -208,7 +234,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
return;
|
||||
}
|
||||
String servers[] = data
|
||||
.getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
.getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS);
|
||||
sPreferences.setKeyServers(servers);
|
||||
mKeyServerPreference.setSummary(keyserverSummary(getActivity()));
|
||||
break;
|
||||
@@ -287,6 +313,7 @@ public class PreferencesActivity extends PreferenceActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
protected boolean isValidFragment(String fragmentName) {
|
||||
return AdvancedPrefsFragment.class.getName().equals(fragmentName)
|
||||
|| CloudSearchPrefsFragment.class.getName().equals(fragmentName)
|
||||
@@ -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,14 +27,13 @@ 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;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public class PreferencesKeyServerActivity extends ActionBarActivity implements OnClickListener,
|
||||
public class SettingsKeyServerActivity extends BaseActivity implements OnClickListener,
|
||||
EditorListener {
|
||||
|
||||
public static final String EXTRA_KEY_SERVERS = "key_servers";
|
||||
@@ -52,23 +50,19 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
|
||||
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();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.key_server_preference);
|
||||
});
|
||||
|
||||
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
@@ -102,6 +96,11 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
|
||||
makeServerList(servers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.key_server_preference);
|
||||
}
|
||||
|
||||
private void makeServerList(String[] servers) {
|
||||
if (servers != null) {
|
||||
mEditors.removeAllViews();
|
||||
@@ -137,7 +136,7 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -150,7 +149,7 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
|
||||
|
||||
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();
|
||||
@@ -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;
|
||||
@@ -44,7 +43,7 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
/**
|
||||
* Sends the selected public key to a keyserver
|
||||
*/
|
||||
public class UploadKeyActivity extends ActionBarActivity {
|
||||
public class UploadKeyActivity extends BaseActivity {
|
||||
private View mUploadButton;
|
||||
private Spinner mKeyServerSpinner;
|
||||
|
||||
@@ -54,12 +53,10 @@ public class UploadKeyActivity extends ActionBarActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.upload_key_activity);
|
||||
|
||||
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()
|
||||
);
|
||||
@@ -86,6 +83,11 @@ public class UploadKeyActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.upload_key_activity);
|
||||
}
|
||||
|
||||
private void uploadKey() {
|
||||
// Send all information needed to service to upload key in other thread
|
||||
Intent intent = new Intent(this, KeychainIntentService.class);
|
||||
|
||||
@@ -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;
|
||||
@@ -49,7 +45,7 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ViewCertActivity extends ActionBarActivity
|
||||
public class ViewCertActivity extends BaseActivity
|
||||
implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
// These are the rows that we will retrieve.
|
||||
@@ -86,8 +82,6 @@ public class ViewCertActivity extends ActionBarActivity
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(R.layout.view_cert_activity);
|
||||
|
||||
mSigneeKey = (TextView) findViewById(R.id.signee_key);
|
||||
mSigneeUid = (TextView) findViewById(R.id.signee_uid);
|
||||
mAlgorithm = (TextView) findViewById(R.id.algorithm);
|
||||
@@ -112,6 +106,11 @@ public class ViewCertActivity extends ActionBarActivity
|
||||
getSupportLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.view_cert_activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
// Now create and return a CursorLoader that will take care of
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
@@ -38,7 +37,6 @@ import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -47,27 +45,26 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.astuetz.PagerSlidingTabStrip;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
|
||||
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout.TabColorizer;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ViewKeyActivity extends ActionBarActivity implements
|
||||
public class ViewKeyActivity extends BaseActivity implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
ExportHelper mExportHelper;
|
||||
@@ -81,7 +78,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
|
||||
|
||||
// view
|
||||
private ViewPager mViewPager;
|
||||
private SlidingTabLayout mSlidingTabLayout;
|
||||
private PagerSlidingTabStrip mSlidingTabLayout;
|
||||
private PagerTabStripAdapter mTabsAdapter;
|
||||
|
||||
private LinearLayout mStatusLayout;
|
||||
@@ -111,27 +108,13 @@ public class ViewKeyActivity extends ActionBarActivity implements
|
||||
actionBar.setIcon(android.R.color.transparent);
|
||||
actionBar.setHomeButtonEnabled(true);
|
||||
|
||||
setContentView(R.layout.view_key_activity);
|
||||
|
||||
mStatusLayout = (LinearLayout) findViewById(R.id.view_key_status_layout);
|
||||
mStatusText = (TextView) findViewById(R.id.view_key_status_text);
|
||||
mStatusImage = (ImageView) findViewById(R.id.view_key_status_image);
|
||||
mStatusDivider = findViewById(R.id.view_key_status_divider);
|
||||
|
||||
mViewPager = (ViewPager) findViewById(R.id.view_key_pager);
|
||||
mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout);
|
||||
|
||||
mSlidingTabLayout.setCustomTabColorizer(new TabColorizer() {
|
||||
@Override
|
||||
public int getIndicatorColor(int position) {
|
||||
return 0xFFAA66CC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDividerColor(int position) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.view_key_sliding_tab_layout);
|
||||
|
||||
int switchToTab = TAB_MAIN;
|
||||
Intent intent = getIntent();
|
||||
@@ -169,6 +152,11 @@ public class ViewKeyActivity extends ActionBarActivity implements
|
||||
mViewPager.setCurrentItem(switchToTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.view_key_activity);
|
||||
}
|
||||
|
||||
private void initTabs(Uri dataUri) {
|
||||
mTabsAdapter = new PagerTabStripAdapter(this);
|
||||
mViewPager.setAdapter(mTabsAdapter);
|
||||
|
||||
@@ -20,18 +20,15 @@ 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;
|
||||
|
||||
public class ViewKeyAdvancedActivity extends ActionBarActivity {
|
||||
public class ViewKeyAdvancedActivity extends BaseActivity {
|
||||
|
||||
ExportHelper mExportHelper;
|
||||
ProviderHelper mProviderHelper;
|
||||
@@ -44,8 +41,7 @@ public class ViewKeyAdvancedActivity extends ActionBarActivity {
|
||||
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) {
|
||||
@@ -55,8 +51,6 @@ public class ViewKeyAdvancedActivity extends ActionBarActivity {
|
||||
}
|
||||
);
|
||||
|
||||
setContentView(R.layout.view_key_advanced_activity);
|
||||
|
||||
Uri dataUri = getIntent().getData();
|
||||
if (dataUri == null) {
|
||||
Log.e(Constants.TAG, "Data missing. Should be uri of key!");
|
||||
@@ -69,6 +63,10 @@ public class ViewKeyAdvancedActivity extends ActionBarActivity {
|
||||
startFragment(savedInstanceState, dataUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
setContentView(R.layout.view_key_advanced_activity);
|
||||
}
|
||||
|
||||
private void startFragment(Bundle savedInstanceState, Uri dataUri) {
|
||||
// However, if we're being restored from a previous state,
|
||||
|
||||
@@ -80,7 +80,7 @@ public class ViewKeyAdvancedFragment extends LoaderFragment implements
|
||||
static final String CERTS_SORT_ORDER =
|
||||
KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.RANK + " ASC, "
|
||||
+ KeychainContract.Certs.VERIFIED + " DESC, "
|
||||
+ KeychainContract.Certs.TYPE + " DESC, "
|
||||
+ KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.TYPE + " DESC, "
|
||||
+ KeychainContract.Certs.SIGNER_UID + " ASC";
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,10 +37,10 @@ import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||
@@ -199,7 +199,7 @@ public class ViewKeyMainFragment extends LoaderFragment implements
|
||||
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
|
||||
}
|
||||
case LOADER_ID_USER_IDS: {
|
||||
Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
|
||||
Uri baseUri = UserPackets.buildUserIdsUri(mDataUri);
|
||||
return new CursorLoader(getActivity(), baseUri,
|
||||
UserIdsAdapter.USER_IDS_PROJECTION, null, null, null);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ 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>>> {
|
||||
@@ -55,8 +54,8 @@ public class ImportKeysListLoader
|
||||
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 +72,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 +139,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Typeface;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -32,10 +31,9 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
|
||||
@@ -47,12 +45,12 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
|
||||
private SaveKeyringParcel mSaveKeyringParcel;
|
||||
|
||||
public static final String[] USER_IDS_PROJECTION = new String[]{
|
||||
UserIds._ID,
|
||||
UserIds.USER_ID,
|
||||
UserIds.RANK,
|
||||
UserIds.VERIFIED,
|
||||
UserIds.IS_PRIMARY,
|
||||
UserIds.IS_REVOKED
|
||||
UserPackets._ID,
|
||||
UserPackets.USER_ID,
|
||||
UserPackets.RANK,
|
||||
UserPackets.VERIFIED,
|
||||
UserPackets.IS_PRIMARY,
|
||||
UserPackets.IS_REVOKED
|
||||
};
|
||||
private static final int INDEX_ID = 0;
|
||||
private static final int INDEX_USER_ID = 1;
|
||||
@@ -223,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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.sufficientlysecure.keychain.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.DialogInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -30,6 +31,8 @@ import android.widget.Toast;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DeleteFileDialogFragment extends DialogFragment {
|
||||
private static final String ARG_DELETE_URI = "delete_uri";
|
||||
|
||||
@@ -69,21 +72,38 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
String scheme = deleteUri.getScheme();
|
||||
|
||||
// We can not securely delete Uris, so just use usual delete on them
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
|
||||
if(scheme.equals(ContentResolver.SCHEME_FILE)) {
|
||||
if(new File(deleteUri.getPath()).delete()) {
|
||||
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(scheme.equals(ContentResolver.SCHEME_CONTENT)) {
|
||||
// We can not securely delete Uris, so just use usual delete on them
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
|
||||
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
|
||||
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete
|
||||
// via the path of the Uri
|
||||
if(new File(deleteUri.getPath()).delete()) {
|
||||
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
|
||||
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, deleteFilename), Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed,
|
||||
deleteFilename), Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Note: We can't delete every file...
|
||||
// If possible we should find out if deletion is possible before even showing the option to do so.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user