Merge branch 'development' into linked-identities
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
@@ -3,11 +3,25 @@ apply plugin: 'witness'
|
||||
|
||||
dependencies {
|
||||
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
||||
// NOTE: libraries are pinned to a specific build, see below
|
||||
|
||||
// from local Android SDK
|
||||
compile 'com.android.support:support-v4:21.0.3'
|
||||
compile 'com.android.support:appcompat-v7:21.0.3'
|
||||
compile 'com.android.support:recyclerview-v7:21.0.3'
|
||||
compile 'com.android.support:cardview-v7:21.0.3'
|
||||
|
||||
// JCenter etc.
|
||||
compile 'com.eftimoff:android-patternview:1.0.1@aar'
|
||||
compile 'com.journeyapps:zxing-android-embedded:2.0.1@aar'
|
||||
compile 'com.journeyapps:zxing-android-integration:2.0.1@aar'
|
||||
compile 'com.google.zxing:core:3.0.1'
|
||||
compile 'com.jpardogo.materialtabstrip:library:1.0.9'
|
||||
compile 'it.neokree:MaterialNavigationDrawer:1.3.1'
|
||||
compile 'com.nispok:snackbar:2.9.1'
|
||||
compile 'com.getbase:floatingactionbutton:1.8.0'
|
||||
|
||||
// libs as submodules
|
||||
compile project(':extern:openpgp-api-lib')
|
||||
compile project(':extern:openkeychain-api-lib')
|
||||
compile project(':extern:html-textview')
|
||||
@@ -20,16 +34,6 @@ dependencies {
|
||||
compile project(':extern:KeybaseLib:Lib')
|
||||
compile project(':extern:TokenAutoComplete:library')
|
||||
compile project(':extern:safeslinger-exchange')
|
||||
|
||||
// NOTE: libraries are pinned to a specific build, see below
|
||||
compile 'com.eftimoff:android-patternview:1.0.0@aar'
|
||||
compile 'com.journeyapps:zxing-android-embedded:2.0.1@aar'
|
||||
compile 'com.journeyapps:zxing-android-integration:2.0.1@aar'
|
||||
compile 'com.google.zxing:core:3.0.1'
|
||||
compile 'com.jpardogo.materialtabstrip:library:1.0.9'
|
||||
compile 'it.neokree:MaterialNavigationDrawer:1.3.1'
|
||||
compile 'com.nispok:snackbar:2.9.1'
|
||||
compile 'com.getbase:floatingactionbutton:1.8.0'
|
||||
}
|
||||
|
||||
// Output of ./gradlew -q calculateChecksums
|
||||
@@ -40,6 +44,16 @@ dependencyVerification {
|
||||
'com.android.support:appcompat-v7:5dbeb5316d0a6027d646ae552804c3baa5e3bd53f7f33db50904d51505c8a0e5',
|
||||
'com.android.support:recyclerview-v7:e525ad3f33c84bb12b73d2dc975b55364a53f0f2d0697e043efba59ba73e22d2',
|
||||
'com.android.support:cardview-v7:45c48c2ab056bc7a8573970b10f8902742c5d443f180dae43c56557397ac39af',
|
||||
'com.eftimoff:android-patternview:cec80e7265b8d8278b3c55b5fcdf551e4600ac2c8bf60d8dd76adca538af0b1e',
|
||||
'com.journeyapps:zxing-android-embedded:5d6ba3931bd0b999695e363b571e95bd6bc9956340c1e6ce740cd0bff3d89a50',
|
||||
'com.journeyapps:zxing-android-integration:6f50bb07c057ac94319777ddfbb66f5d4f6190393418b2fc861e0e60d06f3c0d',
|
||||
'com.google.zxing:core:38c49045765281e4c170062fa3f48e4e988629bf985cab850c7497be5eaa72a1',
|
||||
'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa',
|
||||
'it.neokree:MaterialNavigationDrawer:1174d751a54689fccf53c1fbcdf439745926ae19024f4f1017afb6b29643c57d',
|
||||
'com.nispok:snackbar:59dc092a44c877e9ce5f9040c632d99e62d8932b0a4d67ba0ec9e35467d9047c',
|
||||
'com.getbase:floatingactionbutton:e63966148212e9685afad2370780ea239b6dbd2a06f6a3f919b98882318e6a32',
|
||||
'com.android.support:support-annotations:fdee2354787ef66b268e75958de3f7f6c4f8f325510a6dac9f49c929f83a63de',
|
||||
'com.balysv:material-ripple:587f19c1e27f16c7dc67ff9ac73838aa1451086ef05a15cee38bee3e4e1454ae',
|
||||
//'OpenKeychain.extern:openpgp-api-lib:b17bb282321351e4b00b4cd6422a57aadc13decae264019a88707bcb556439ea',
|
||||
//'OpenKeychain.extern:openkeychain-api-lib:5f95f01c066069d4bde68992fd8da5faac21510d009b1fdae7a2e28e43e82cf4',
|
||||
//'OpenKeychain.extern:html-textview:b58e343cf4c145e91f888806d06a2a7770a9e9331a72f08cfcf1128db30dcff3',
|
||||
@@ -52,16 +66,6 @@ dependencyVerification {
|
||||
//'OpenKeychain.extern.KeybaseLib:Lib:af9bff087148e0859430d0b99ece096c41b315c5dc1ed500a68580b9b0e5ab11',
|
||||
//'OpenKeychain.extern.TokenAutoComplete:library:40d4212a95e947efdb02f2ca66c95a27d49fba848471a6317eca2b9cc18e8780',
|
||||
//'OpenKeychain.extern:safeslinger-exchange:94a1ce68217af7499579a042758283b1530912c53241bdfa06d1a079a5ae3faf',
|
||||
'com.eftimoff:android-patternview:a031eaed3b5cef8ea06c2d4a6e27693937f89ae483598d61b7027eeee0bed408',
|
||||
'com.journeyapps:zxing-android-embedded:5d6ba3931bd0b999695e363b571e95bd6bc9956340c1e6ce740cd0bff3d89a50',
|
||||
'com.journeyapps:zxing-android-integration:6f50bb07c057ac94319777ddfbb66f5d4f6190393418b2fc861e0e60d06f3c0d',
|
||||
'com.google.zxing:core:38c49045765281e4c170062fa3f48e4e988629bf985cab850c7497be5eaa72a1',
|
||||
'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa',
|
||||
'it.neokree:MaterialNavigationDrawer:1174d751a54689fccf53c1fbcdf439745926ae19024f4f1017afb6b29643c57d',
|
||||
'com.nispok:snackbar:59dc092a44c877e9ce5f9040c632d99e62d8932b0a4d67ba0ec9e35467d9047c',
|
||||
'com.getbase:floatingactionbutton:e63966148212e9685afad2370780ea239b6dbd2a06f6a3f919b98882318e6a32',
|
||||
'com.android.support:support-annotations:fdee2354787ef66b268e75958de3f7f6c4f8f325510a6dac9f49c929f83a63de',
|
||||
'com.balysv:material-ripple:587f19c1e27f16c7dc67ff9ac73838aa1451086ef05a15cee38bee3e4e1454ae',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -67,10 +67,8 @@
|
||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
||||
|
||||
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
|
||||
<!-- tools:replace="android:allowBackup" is a workaround for https://github.com/geftimov/android-patternview/pull/2 -->
|
||||
<application
|
||||
android:name=".KeychainApplication"
|
||||
tools:replace="android:allowBackup"
|
||||
android:allowBackup="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
|
||||
@@ -33,6 +33,7 @@ public final class Constants {
|
||||
|
||||
public static final String ACCOUNT_NAME = "OpenKeychain";
|
||||
public static final String ACCOUNT_TYPE = PACKAGE_NAME + ".account";
|
||||
public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key";
|
||||
|
||||
// as defined in http://tools.ietf.org/html/rfc3156, section 7
|
||||
public static final String NFC_MIME = "application/pgp-keys";
|
||||
@@ -49,8 +50,6 @@ public final class Constants {
|
||||
public static final String INTENT_PREFIX = PACKAGE_NAME + ".action.";
|
||||
public static final String EXTRA_PREFIX = PACKAGE_NAME + ".";
|
||||
|
||||
public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key";
|
||||
|
||||
public static final int TEMPFILE_TTL = 24 * 60 * 60 * 1000; // 1 day
|
||||
|
||||
public static final String SAFESLINGER_SERVER = "safeslinger-openpgp.appspot.com";
|
||||
|
||||
@@ -140,20 +140,22 @@ public class KeychainApplication extends Application {
|
||||
}
|
||||
|
||||
static void brandGlowEffect(Context context, int brandColor) {
|
||||
try {
|
||||
// terrible hack to brand the edge overscroll glow effect
|
||||
// https://gist.github.com/menny/7878762#file-brandgloweffect_full-java
|
||||
// no hack on Android 5
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
try {
|
||||
// terrible hack to brand the edge overscroll glow effect
|
||||
// https://gist.github.com/menny/7878762#file-brandgloweffect_full-java
|
||||
|
||||
//glow
|
||||
int glowDrawableId = context.getResources().getIdentifier("overscroll_glow", "drawable", "android");
|
||||
Drawable androidGlow = context.getResources().getDrawable(glowDrawableId);
|
||||
androidGlow.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN);
|
||||
//edge
|
||||
int edgeDrawableId = context.getResources().getIdentifier("overscroll_edge", "drawable", "android");
|
||||
Drawable androidEdge = context.getResources().getDrawable(edgeDrawableId);
|
||||
androidEdge.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
// no hack on Android 5
|
||||
//glow
|
||||
int glowDrawableId = context.getResources().getIdentifier("overscroll_glow", "drawable", "android");
|
||||
Drawable androidGlow = context.getResources().getDrawable(glowDrawableId);
|
||||
androidGlow.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN);
|
||||
//edge
|
||||
int edgeDrawableId = context.getResources().getIdentifier("overscroll_edge", "drawable", "android");
|
||||
Drawable androidEdge = context.getResources().getDrawable(edgeDrawableId);
|
||||
androidEdge.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** Represent the result of an operation.
|
||||
*
|
||||
@@ -51,6 +53,56 @@ import java.util.List;
|
||||
public abstract class OperationResult implements Parcelable {
|
||||
|
||||
public static final String EXTRA_RESULT = "operation_result";
|
||||
public static final UUID NULL_UUID = new UUID(0,0);
|
||||
|
||||
/**
|
||||
* A HashMap of UUID:OperationLog which contains logs that we don't need
|
||||
* to care about. This is used such that when we become parceled, we are
|
||||
* well below the 1Mbit boundary that is specified.
|
||||
*/
|
||||
private static ConcurrentHashMap<UUID, OperationLog> dehydratedLogs;
|
||||
static {
|
||||
// Static initializer for ConcurrentHashMap
|
||||
dehydratedLogs = new ConcurrentHashMap<UUID,OperationLog>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dehydrate a log (such that it is available after deparcelization)
|
||||
*
|
||||
* Returns the NULL uuid (0) if you hand it null.
|
||||
* @param log An OperationLog to dehydrate
|
||||
* @return a UUID, the ticket for your dehydrated log
|
||||
*
|
||||
*/
|
||||
private static UUID dehydrateLog(OperationLog log) {
|
||||
if(log == null) {
|
||||
return NULL_UUID;
|
||||
}
|
||||
else {
|
||||
UUID ticket = UUID.randomUUID();
|
||||
dehydratedLogs.put(ticket, log);
|
||||
return ticket;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Rehydrate a log after going through parcelization, invalidating its place in the
|
||||
* dehydration pool.
|
||||
* This is used such that when parcelized, the parcel is no larger than 1mbit.
|
||||
* @param ticket A UUID ticket that identifies the log in question.
|
||||
* @return An OperationLog.
|
||||
*/
|
||||
private static OperationLog rehydrateLog(UUID ticket) {
|
||||
// UUID.equals isn't well documented; we use compareTo instead.
|
||||
if( NULL_UUID.compareTo(ticket) == 0 ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
OperationLog log = dehydratedLogs.get(ticket);
|
||||
dehydratedLogs.remove(ticket);
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds the overall result, the number specifying varying degrees of success:
|
||||
* - The first bit is 0 on overall success, 1 on overall failure
|
||||
@@ -65,7 +117,7 @@ public abstract class OperationResult implements Parcelable {
|
||||
public static final int RESULT_WARNINGS = 4;
|
||||
|
||||
/// A list of log entries tied to the operation result.
|
||||
final OperationLog mLog;
|
||||
protected OperationLog mLog;
|
||||
|
||||
public OperationResult(int result, OperationLog log) {
|
||||
mResult = result;
|
||||
@@ -74,8 +126,11 @@ public abstract class OperationResult implements Parcelable {
|
||||
|
||||
public OperationResult(Parcel source) {
|
||||
mResult = source.readInt();
|
||||
mLog = new OperationLog();
|
||||
mLog.addAll(source.createTypedArrayList(LogEntryParcel.CREATOR));
|
||||
long mostSig = source.readLong();
|
||||
long leastSig = source.readLong();
|
||||
UUID mTicket = new UUID(mostSig, leastSig);
|
||||
// fetch the dehydrated log out of storage (this removes it from the dehydration pool)
|
||||
mLog = rehydrateLog(mTicket);
|
||||
}
|
||||
|
||||
public int getResult() {
|
||||
@@ -723,6 +778,12 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_LV_FETCH_ERROR_URL (LogLevel.ERROR, R.string.msg_lv_fetch_error_url),
|
||||
MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io),
|
||||
|
||||
//export log
|
||||
MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start),
|
||||
MSG_EXPORT_LOG_EXPORT_ERROR_NO_FILE(LogLevel.ERROR,R.string.msg_export_log_error_no_file),
|
||||
MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen),
|
||||
MSG_EXPORT_LOG_EXPORT_ERROR_WRITING(LogLevel.ERROR,R.string.msg_export_log_error_writing),
|
||||
MSG_EXPORT_LOG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_log_success),
|
||||
;
|
||||
|
||||
public final int mMsgId;
|
||||
@@ -755,9 +816,11 @@ public abstract class OperationResult implements Parcelable {
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mResult);
|
||||
if (mLog != null) {
|
||||
dest.writeTypedList(mLog.toList());
|
||||
}
|
||||
// Get a ticket for our log.
|
||||
UUID mTicket = dehydrateLog(mLog);
|
||||
// And write out the UUID most and least significant bits.
|
||||
dest.writeLong(mTicket.getMostSignificantBits());
|
||||
dest.writeLong(mTicket.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
public static class OperationLog implements Iterable<LogEntryParcel> {
|
||||
|
||||
@@ -100,8 +100,8 @@ public class PgpKeyOperation {
|
||||
private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{
|
||||
HashAlgorithmTags.SHA512,
|
||||
HashAlgorithmTags.SHA384,
|
||||
HashAlgorithmTags.SHA224,
|
||||
HashAlgorithmTags.SHA256,
|
||||
HashAlgorithmTags.SHA224,
|
||||
HashAlgorithmTags.RIPEMD160
|
||||
};
|
||||
private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
|
||||
@@ -131,6 +131,7 @@ public class PgpKeyOperation {
|
||||
private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x90;
|
||||
private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA256;
|
||||
private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
|
||||
private static final int SECRET_KEY_SIGNATURE_HASH_ALGO = HashAlgorithmTags.SHA256;
|
||||
|
||||
public PgpKeyOperation(Progressable progress) {
|
||||
super();
|
||||
@@ -1025,7 +1026,7 @@ public class PgpKeyOperation {
|
||||
|
||||
// add packet with EMPTY notation data (updates old one, but will be stripped later)
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
{ // set subpackets
|
||||
@@ -1051,7 +1052,7 @@ public class PgpKeyOperation {
|
||||
|
||||
// add packet with "pin" notation data
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
{ // set subpackets
|
||||
@@ -1236,7 +1237,7 @@ public class PgpKeyOperation {
|
||||
int flags, long expiry)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
@@ -1279,7 +1280,7 @@ public class PgpKeyOperation {
|
||||
PGPUserAttributeSubpacketVector vector)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
@@ -1298,7 +1299,7 @@ public class PgpKeyOperation {
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
@@ -1312,7 +1313,7 @@ public class PgpKeyOperation {
|
||||
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPublicKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
@@ -1356,7 +1357,7 @@ public class PgpKeyOperation {
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
pKey.getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
pKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
|
||||
@@ -1377,7 +1378,7 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
|
||||
masterPublicKey.getAlgorithm(), SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
|
||||
|
||||
@@ -28,9 +28,11 @@ public class CreateKeyActivity extends BaseActivity {
|
||||
public static final String EXTRA_NAME = "name";
|
||||
public static final String EXTRA_EMAIL = "email";
|
||||
|
||||
public static final int FRAG_ACTION_START = 0;
|
||||
public static final int FRAG_ACTION_TO_RIGHT = 1;
|
||||
public static final int FRAG_ACTION_TO_LEFT = 2;
|
||||
public static enum FragAction {
|
||||
START,
|
||||
TO_RIGHT,
|
||||
TO_LEFT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -42,7 +44,7 @@ public class CreateKeyActivity extends BaseActivity {
|
||||
getIntent().getStringExtra(EXTRA_NAME),
|
||||
getIntent().getStringExtra(EXTRA_EMAIL)
|
||||
);
|
||||
loadFragment(null, frag, FRAG_ACTION_START);
|
||||
loadFragment(null, frag, FragAction.START);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +52,7 @@ public class CreateKeyActivity extends BaseActivity {
|
||||
setContentView(R.layout.create_key_activity);
|
||||
}
|
||||
|
||||
public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) {
|
||||
public void loadFragment(Bundle savedInstanceState, Fragment fragment, FragAction action) {
|
||||
// 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.
|
||||
@@ -63,15 +65,15 @@ public class CreateKeyActivity extends BaseActivity {
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
|
||||
switch (action) {
|
||||
case FRAG_ACTION_START:
|
||||
case START:
|
||||
transaction.setCustomAnimations(0, 0);
|
||||
transaction.replace(R.id.create_key_fragment_container, fragment)
|
||||
.commitAllowingStateLoss();
|
||||
break;
|
||||
case FRAG_ACTION_TO_LEFT:
|
||||
case TO_LEFT:
|
||||
getSupportFragmentManager().popBackStackImmediate();
|
||||
break;
|
||||
case FRAG_ACTION_TO_RIGHT:
|
||||
case TO_RIGHT:
|
||||
transaction.setCustomAnimations(R.anim.frag_slide_in_from_right, R.anim.frag_slide_out_to_left,
|
||||
R.anim.frag_slide_in_from_left, R.anim.frag_slide_out_to_right);
|
||||
transaction.addToBackStack(null);
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
@@ -117,7 +118,7 @@ public class CreateKeyFinalFragment extends Fragment {
|
||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCreateKeyActivity.loadFragment(null, null, CreateKeyActivity.FRAG_ACTION_TO_LEFT);
|
||||
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.widget.AutoCompleteTextView;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
@@ -161,7 +162,7 @@ public class CreateKeyInputFragment extends Fragment {
|
||||
);
|
||||
|
||||
hideKeyboard();
|
||||
mCreateKeyActivity.loadFragment(null, frag, CreateKeyActivity.FRAG_ACTION_TO_RIGHT);
|
||||
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
public abstract class DecryptFragment extends Fragment {
|
||||
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
|
||||
@@ -141,16 +142,16 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
if (signatureResult.isSignatureOnly()) {
|
||||
mEncryptionText.setText(R.string.decrypt_result_not_encrypted);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, KeyFormattingUtils.STATE_NOT_ENCRYPTED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.NOT_ENCRYPTED);
|
||||
} else {
|
||||
mEncryptionText.setText(R.string.decrypt_result_encrypted);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, KeyFormattingUtils.STATE_ENCRYPTED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED);
|
||||
}
|
||||
|
||||
switch (signatureResult.getStatus()) {
|
||||
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
|
||||
mSignatureText.setText(R.string.decrypt_result_signature_certified);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_VERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.VERIFIED);
|
||||
|
||||
setSignatureLayoutVisibility(View.VISIBLE);
|
||||
setShowAction(mSignatureKeyId);
|
||||
@@ -161,7 +162,7 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
|
||||
mSignatureText.setText(R.string.decrypt_result_signature_uncertified);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_UNVERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNVERIFIED);
|
||||
|
||||
setSignatureLayoutVisibility(View.VISIBLE);
|
||||
setShowAction(mSignatureKeyId);
|
||||
@@ -172,11 +173,11 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: {
|
||||
mSignatureText.setText(R.string.decrypt_result_signature_missing_key);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_UNKNOWN_KEY);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNKNOWN_KEY);
|
||||
|
||||
setSignatureLayoutVisibility(View.VISIBLE);
|
||||
mSignatureAction.setText(R.string.decrypt_result_action_Lookup);
|
||||
mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_download, 0);
|
||||
mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_file_download_grey_24dp, 0);
|
||||
mSignatureLayout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -190,7 +191,7 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
|
||||
mSignatureText.setText(R.string.decrypt_result_signature_expired_key);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_EXPIRED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.EXPIRED);
|
||||
|
||||
setSignatureLayoutVisibility(View.VISIBLE);
|
||||
setShowAction(mSignatureKeyId);
|
||||
@@ -201,7 +202,7 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
|
||||
mSignatureText.setText(R.string.decrypt_result_signature_revoked_key);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_REVOKED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.REVOKED);
|
||||
|
||||
setSignatureLayoutVisibility(View.VISIBLE);
|
||||
setShowAction(mSignatureKeyId);
|
||||
@@ -212,7 +213,7 @@ public abstract class DecryptFragment extends Fragment {
|
||||
|
||||
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
|
||||
mSignatureText.setText(R.string.decrypt_result_invalid_signature);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_INVALID);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.INVALID);
|
||||
|
||||
setSignatureLayoutVisibility(View.GONE);
|
||||
|
||||
@@ -224,9 +225,9 @@ public abstract class DecryptFragment extends Fragment {
|
||||
setSignatureLayoutVisibility(View.GONE);
|
||||
|
||||
mSignatureText.setText(R.string.decrypt_result_no_signature);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_NOT_SIGNED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.NOT_SIGNED);
|
||||
mEncryptionText.setText(R.string.decrypt_result_encrypted);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, KeyFormattingUtils.STATE_ENCRYPTED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED);
|
||||
|
||||
valid = true;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,9 @@ public class HelpActivity extends BaseActivity {
|
||||
|
||||
public static final int TAB_START = 0;
|
||||
public static final int TAB_FAQ = 1;
|
||||
public static final int TAB_WOT = 2;
|
||||
public static final int TAB_NFC = 3;
|
||||
public static final int TAB_CHANGELOG = 4;
|
||||
public static final int TAB_ABOUT = 5;
|
||||
public static final int TAB_TRUST = 2;
|
||||
public static final int TAB_CHANGELOG = 3;
|
||||
public static final int TAB_ABOUT = 4;
|
||||
|
||||
ViewPager mViewPager;
|
||||
private PagerTabStripAdapter mTabsAdapter;
|
||||
@@ -69,21 +68,11 @@ public class HelpActivity extends BaseActivity {
|
||||
mTabsAdapter.addTab(HelpHtmlFragment.class, startBundle,
|
||||
getString(R.string.help_tab_start));
|
||||
|
||||
Bundle faqBundle = new Bundle();
|
||||
faqBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_faq);
|
||||
mTabsAdapter.addTab(HelpHtmlFragment.class, faqBundle,
|
||||
getString(R.string.help_tab_faq));
|
||||
|
||||
Bundle wotBundle = new Bundle();
|
||||
wotBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_wot);
|
||||
wotBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_certification);
|
||||
mTabsAdapter.addTab(HelpHtmlFragment.class, wotBundle,
|
||||
getString(R.string.help_tab_wot));
|
||||
|
||||
Bundle nfcBundle = new Bundle();
|
||||
nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam);
|
||||
mTabsAdapter.addTab(HelpHtmlFragment.class, nfcBundle,
|
||||
getString(R.string.help_tab_nfc_beam));
|
||||
|
||||
Bundle changelogBundle = new Bundle();
|
||||
changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog);
|
||||
mTabsAdapter.addTab(HelpHtmlFragment.class, changelogBundle,
|
||||
|
||||
@@ -70,6 +70,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.FabContainer;
|
||||
@@ -77,7 +78,6 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
||||
@@ -268,7 +268,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.EXPIRY,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET
|
||||
};
|
||||
@@ -276,7 +276,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
static final int INDEX_MASTER_KEY_ID = 1;
|
||||
static final int INDEX_USER_ID = 2;
|
||||
static final int INDEX_IS_REVOKED = 3;
|
||||
static final int INDEX_EXPIRY = 4;
|
||||
static final int INDEX_IS_EXPIRED = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
|
||||
@@ -708,21 +708,20 @@ public class KeyListFragment extends LoaderFragment
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
|
||||
&& new Date(cursor.getLong(INDEX_EXPIRY) * 1000).before(new Date());
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
|
||||
|
||||
h.mMasterKeyId = masterKeyId;
|
||||
|
||||
// Note: order is important!
|
||||
if (isRevoked) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.REVOKED, R.color.bg_gray);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
} else if (isExpired) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.EXPIRED, R.color.bg_gray);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
@@ -735,10 +734,10 @@ public class KeyListFragment extends LoaderFragment
|
||||
} else {
|
||||
// this is a public key - show if it's verified
|
||||
if (isVerified) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, KeyFormattingUtils.STATE_VERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.VERIFIED);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, KeyFormattingUtils.STATE_UNVERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.UNVERIFIED);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
}
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
|
||||
@@ -22,9 +22,13 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
@@ -33,11 +37,19 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class LogDisplayFragment extends ListFragment implements OnItemClickListener {
|
||||
|
||||
@@ -46,6 +58,12 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
|
||||
OperationResult mResult;
|
||||
|
||||
public static final String EXTRA_RESULT = "log";
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
@@ -70,6 +88,183 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
|
||||
|
||||
getListView().setFastScrollEnabled(true);
|
||||
getListView().setDividerHeight(0);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.log_display, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_log_display_export_log:
|
||||
exportLog();
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void exportLog() {
|
||||
|
||||
showExportLogDialog(new File(Constants.Path.APP_DIR, "export.log"));
|
||||
}
|
||||
|
||||
private void writeToLogFile(final OperationResult.OperationLog operationLog, final File f) {
|
||||
OperationResult.OperationLog currLog = new OperationResult.OperationLog();
|
||||
currLog.add(OperationResult.LogType.MSG_EXPORT_LOG, 0);
|
||||
|
||||
boolean error = false;
|
||||
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
pw = new PrintWriter(f);
|
||||
pw.print(getPrintableOperationLog(operationLog, ""));
|
||||
if (pw.checkError()) {//IOException
|
||||
Log.e(Constants.TAG, "Log Export I/O Exception " + f.getAbsolutePath());
|
||||
currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_WRITING, 1);
|
||||
error = true;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(Constants.TAG, "File not found for exporting log " + f.getAbsolutePath());
|
||||
currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN, 1);
|
||||
error = true;
|
||||
}
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
if (!error && pw.checkError()) {//check if it is only pw.close() which generated error
|
||||
currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_WRITING, 1);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_SUCCESS, 1);
|
||||
|
||||
int opResultCode = error ? OperationResult.RESULT_ERROR : OperationResult.RESULT_OK;
|
||||
OperationResult opResult = new LogExportResult(opResultCode, currLog);
|
||||
opResult.createNotify(getActivity()).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an indented String of an entire OperationLog
|
||||
*
|
||||
* @param opLog log to be converted to indented, printable format
|
||||
* @param basePadding padding to add at the start of all log entries, made for use with SubLogs
|
||||
* @return printable, indented version of passed operationLog
|
||||
*/
|
||||
private String getPrintableOperationLog(OperationResult.OperationLog opLog, String basePadding) {
|
||||
String log = "";
|
||||
for (Iterator<LogEntryParcel> logIterator = opLog.iterator(); logIterator.hasNext(); ) {
|
||||
log += getPrintableLogEntry(logIterator.next(), basePadding) + "\n";
|
||||
}
|
||||
log = log.substring(0, log.length() - 1);//gets rid of extra new line
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an indented String of a LogEntryParcel including any sub-logs it may contain
|
||||
*
|
||||
* @param entryParcel log entryParcel whose String representation is to be obtained
|
||||
* @return indented version of passed log entryParcel in a readable format
|
||||
*/
|
||||
private String getPrintableLogEntry(OperationResult.LogEntryParcel entryParcel,
|
||||
String basePadding) {
|
||||
|
||||
final String indent = " ";//4 spaces = 1 Indent level
|
||||
|
||||
String padding = basePadding;
|
||||
for (int i = 0; i < entryParcel.mIndent; i++) {
|
||||
padding += indent;
|
||||
}
|
||||
String logText = padding;
|
||||
|
||||
switch (entryParcel.mType.mLevel) {
|
||||
case DEBUG:
|
||||
logText += "[DEBUG]";
|
||||
break;
|
||||
case INFO:
|
||||
logText += "[INFO]";
|
||||
break;
|
||||
case WARN:
|
||||
logText += "[WARN]";
|
||||
break;
|
||||
case ERROR:
|
||||
logText += "[ERROR]";
|
||||
break;
|
||||
case START:
|
||||
logText += "[START]";
|
||||
break;
|
||||
case OK:
|
||||
logText += "[OK]";
|
||||
break;
|
||||
case CANCELLED:
|
||||
logText += "[CANCELLED]";
|
||||
break;
|
||||
}
|
||||
|
||||
// special case: first parameter may be a quantity
|
||||
if (entryParcel.mParameters != null && entryParcel.mParameters.length > 0
|
||||
&& entryParcel.mParameters[0] instanceof Integer) {
|
||||
logText += getResources().getQuantityString(entryParcel.mType.getMsgId(),
|
||||
(Integer) entryParcel.mParameters[0],
|
||||
entryParcel.mParameters);
|
||||
} else {
|
||||
logText += getResources().getString(entryParcel.mType.getMsgId(),
|
||||
entryParcel.mParameters);
|
||||
}
|
||||
|
||||
if (entryParcel instanceof SubLogEntryParcel) {
|
||||
OperationResult subResult = ((SubLogEntryParcel) entryParcel).getSubResult();
|
||||
LogEntryParcel subEntry = subResult.getLog().getLast();
|
||||
if (subEntry != null) {
|
||||
//the first line of log of subResult is same as entryParcel, so replace logText
|
||||
logText = getPrintableOperationLog(subResult.getLog(), padding);
|
||||
}
|
||||
}
|
||||
|
||||
return logText;
|
||||
}
|
||||
|
||||
private void showExportLogDialog(final File exportFile) {
|
||||
|
||||
String title = this.getString(R.string.title_export_log);
|
||||
|
||||
String message = this.getString(R.string.specify_file_to_export_log_to);
|
||||
|
||||
FileHelper.saveFile(new FileHelper.FileDialogCallback() {
|
||||
@Override
|
||||
public void onFileSelected(File file, boolean checked) {
|
||||
writeToLogFile(mResult.getLog(), file);
|
||||
}
|
||||
}, this.getActivity().getSupportFragmentManager(), title, message, exportFile, null);
|
||||
}
|
||||
|
||||
private static class LogExportResult extends OperationResult {
|
||||
|
||||
public static Creator<LogExportResult> CREATOR = new Creator<LogExportResult>() {
|
||||
public LogExportResult createFromParcel(final Parcel source) {
|
||||
return new LogExportResult(source);
|
||||
}
|
||||
|
||||
public LogExportResult[] newArray(final int size) {
|
||||
return new LogExportResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
public LogExportResult(int result, OperationLog log) {
|
||||
super(result, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* trivial but necessary to implement the Parcelable protocol.
|
||||
*/
|
||||
public LogExportResult(Parcel source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,7 +304,7 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
|
||||
mSecondImg = secondImg;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if convertView.setPadding is redundant
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
LogEntryParcel entry = getItem(position);
|
||||
@@ -132,7 +327,6 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
|
||||
if (entry instanceof SubLogEntryParcel) {
|
||||
ih.mSub.setVisibility(View.VISIBLE);
|
||||
convertView.setClickable(false);
|
||||
|
||||
convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);
|
||||
|
||||
OperationResult result = ((SubLogEntryParcel) entry).getSubResult();
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
@@ -149,6 +150,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
|
||||
public static class PassphraseDialogFragment extends DialogFragment implements TextView.OnEditorActionListener {
|
||||
private EditText mPassphraseEditText;
|
||||
private TextView mPassphraseText;
|
||||
private View mInput, mProgress;
|
||||
|
||||
private CanonicalizedSecretKeyRing mSecretRing = null;
|
||||
@@ -167,7 +169,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
// if the dialog is displayed from the application class, design is missing
|
||||
// hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
|
||||
ContextThemeWrapper theme = new ContextThemeWrapper(activity,
|
||||
R.style.Theme_AppCompat_Light);
|
||||
R.style.Theme_AppCompat_Light_Dialog);
|
||||
|
||||
mSubKeyId = getArguments().getLong(EXTRA_SUBKEY_ID);
|
||||
mServiceIntent = getArguments().getParcelable(EXTRA_DATA);
|
||||
@@ -176,13 +178,30 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
|
||||
alert.setTitle(R.string.title_unlock);
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(theme);
|
||||
View view = inflater.inflate(R.layout.passphrase_dialog, null);
|
||||
alert.setView(view);
|
||||
|
||||
mPassphraseText = (TextView) view.findViewById(R.id.passphrase_text);
|
||||
mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
mInput = view.findViewById(R.id.input);
|
||||
mProgress = view.findViewById(R.id.progress);
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
String userId;
|
||||
CanonicalizedSecretKey.SecretKeyType keyType = CanonicalizedSecretKey.SecretKeyType.PASSPHRASE;
|
||||
|
||||
String message;
|
||||
if (mSubKeyId == Constants.key.symmetric || mSubKeyId == Constants.key.none) {
|
||||
alert.setMessage(R.string.passphrase_for_symmetric_encryption);
|
||||
message = getString(R.string.passphrase_for_symmetric_encryption);
|
||||
} else {
|
||||
String message;
|
||||
try {
|
||||
ProviderHelper helper = new ProviderHelper(activity);
|
||||
mSecretRing = helper.getCanonicalizedSecretKeyRing(
|
||||
@@ -191,7 +210,13 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
// above can't be statically verified to have been set in all cases because
|
||||
// the catch clause doesn't return.
|
||||
try {
|
||||
userId = mSecretRing.getPrimaryUserIdWithFallback();
|
||||
String mainUserId = mSecretRing.getPrimaryUserIdWithFallback();
|
||||
String[] mainUserIdSplit = KeyRing.splitUserId(mainUserId);
|
||||
if (mainUserIdSplit[0] != null) {
|
||||
userId = mainUserIdSplit[0];
|
||||
} else {
|
||||
userId = getString(R.string.user_id_no_name);
|
||||
}
|
||||
} catch (PgpKeyNotFoundException e) {
|
||||
userId = null;
|
||||
}
|
||||
@@ -231,33 +256,16 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
alert.setCancelable(false);
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
alert.setMessage(message);
|
||||
}
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(theme);
|
||||
View view = inflater.inflate(R.layout.passphrase_dialog, null);
|
||||
alert.setView(view);
|
||||
|
||||
mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
mInput = view.findViewById(R.id.input);
|
||||
mProgress = view.findViewById(R.id.progress);
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
mPassphraseText.setText(message);
|
||||
|
||||
if (keyType == CanonicalizedSecretKey.SecretKeyType.PATTERN) {
|
||||
// start pattern dialog and show progress circle here...
|
||||
// Intent patternActivity = new Intent(getActivity(), LockPatternActivity.class);
|
||||
// patternActivity.putExtra(LockPatternActivity.EXTRA_PATTERN, "123");
|
||||
// startActivityForResult(patternActivity, REQUEST_CODE_ENTER_PATTERN);
|
||||
mInput.setVisibility(View.GONE);
|
||||
mInput.setVisibility(View.INVISIBLE);
|
||||
mProgress.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
// Hack to open keyboard.
|
||||
@@ -325,7 +333,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
mInput.setVisibility(View.GONE);
|
||||
mInput.setVisibility(View.INVISIBLE);
|
||||
mProgress.setVisibility(View.VISIBLE);
|
||||
positive.setEnabled(false);
|
||||
|
||||
@@ -367,7 +375,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
||||
mPassphraseEditText.setText("");
|
||||
mPassphraseEditText.setError(getString(R.string.wrong_passphrase));
|
||||
mInput.setVisibility(View.VISIBLE);
|
||||
mProgress.setVisibility(View.GONE);
|
||||
mProgress.setVisibility(View.INVISIBLE);
|
||||
positive.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
@@ -136,7 +137,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
|
||||
mSearchView.setId(SEARCH_ID);
|
||||
mSearchView.setHint(R.string.menu_search);
|
||||
mSearchView.setCompoundDrawablesWithIntrinsicBounds(
|
||||
getResources().getDrawable(R.drawable.ic_action_search), null, null, null);
|
||||
getResources().getDrawable(R.drawable.ic_search_grey_24dp), null, null, null);
|
||||
|
||||
linearLayout.addView(mSearchView, new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
@@ -376,15 +377,15 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
|
||||
// Check if key is viable for our purposes
|
||||
if (cursor.getInt(mIndexHasEncrypt) == 0) {
|
||||
h.statusIcon.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, KeyFormattingUtils.STATE_UNAVAILABLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, State.UNAVAILABLE);
|
||||
enabled = false;
|
||||
} else if (cursor.getInt(mIndexIsVerified) != 0) {
|
||||
h.statusIcon.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, KeyFormattingUtils.STATE_VERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, State.VERIFIED);
|
||||
enabled = true;
|
||||
} else {
|
||||
h.statusIcon.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, KeyFormattingUtils.STATE_UNVERIFIED);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, State.UNVERIFIED);
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,16 +75,15 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
||||
import org.sufficientlysecure.keychain.ui.widget.AspectRatioImageView;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ViewKeyActivity extends BaseActivity implements
|
||||
@@ -106,7 +105,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
private ImageButton mActionEncryptText;
|
||||
private ImageButton mActionNfc;
|
||||
private FloatingActionButton mFab;
|
||||
private AspectRatioImageView mPhoto;
|
||||
private ImageView mPhoto;
|
||||
private ImageView mQrCode;
|
||||
private CardView mQrCodeLayout;
|
||||
|
||||
@@ -122,6 +121,9 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
private boolean mIsSecret = false;
|
||||
private boolean mHasEncrypt = false;
|
||||
private boolean mIsVerified = false;
|
||||
private boolean mIsRevoked = false;
|
||||
private boolean mIsExpired = false;
|
||||
|
||||
private MenuItem mRefreshItem;
|
||||
private boolean mIsRefreshing;
|
||||
private Animation mRotate, mRotateSpin;
|
||||
@@ -148,7 +150,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text);
|
||||
mActionNfc = (ImageButton) findViewById(R.id.view_key_action_nfc);
|
||||
mFab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo);
|
||||
mPhoto = (ImageView) findViewById(R.id.view_key_photo);
|
||||
mQrCode = (ImageView) findViewById(R.id.view_key_qr_code);
|
||||
mQrCodeLayout = (CardView) findViewById(R.id.view_key_qr_code_layout);
|
||||
|
||||
@@ -174,7 +176,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
|
||||
}
|
||||
});
|
||||
mRotate = AnimationUtils.loadAnimation(this, R.anim.rotate);
|
||||
mRotate = AnimationUtils.loadAnimation(this, R.anim.rotate);
|
||||
mRotate.setRepeatCount(Animation.INFINITE);
|
||||
mRotate.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
@@ -358,7 +360,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
addLinked.setVisible(mIsSecret);
|
||||
|
||||
MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint);
|
||||
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified);
|
||||
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -409,12 +411,12 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
|
||||
private void certifyImmediate() {
|
||||
Intent intent = new Intent(this, CertifyKeyActivity.class);
|
||||
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{ mMasterKeyId });
|
||||
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
|
||||
|
||||
startCertifyIntent(intent);
|
||||
}
|
||||
|
||||
private void startCertifyIntent (Intent intent) {
|
||||
private void startCertifyIntent(Intent intent) {
|
||||
// Message is received after signing is done in KeychainIntentService
|
||||
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this) {
|
||||
public void handleMessage(Message message) {
|
||||
@@ -761,7 +763,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||
KeychainContract.KeyRings.USER_ID,
|
||||
KeychainContract.KeyRings.IS_REVOKED,
|
||||
KeychainContract.KeyRings.EXPIRY,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.VERIFIED,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET,
|
||||
KeychainContract.KeyRings.FINGERPRINT,
|
||||
@@ -771,7 +773,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
static final int INDEX_MASTER_KEY_ID = 1;
|
||||
static final int INDEX_USER_ID = 2;
|
||||
static final int INDEX_IS_REVOKED = 3;
|
||||
static final int INDEX_EXPIRY = 4;
|
||||
static final int INDEX_IS_EXPIRED = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
static final int INDEX_FINGERPRINT = 7;
|
||||
@@ -820,9 +822,8 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
|
||||
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0;
|
||||
boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = !data.isNull(INDEX_EXPIRY)
|
||||
&& new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date());
|
||||
mIsRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
|
||||
mIsExpired = data.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
mIsVerified = data.getInt(INDEX_VERIFIED) > 0;
|
||||
|
||||
// if the refresh animation isn't playing
|
||||
@@ -832,10 +833,10 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
// this is done at the end of the animation otherwise
|
||||
}
|
||||
|
||||
AsyncTask<String, Void, Bitmap> photoTask =
|
||||
new AsyncTask<String, Void, Bitmap>() {
|
||||
protected Bitmap doInBackground(String... fingerprint) {
|
||||
return ContactHelper.photoFromFingerprint(getContentResolver(), fingerprint[0]);
|
||||
AsyncTask<Long, Void, Bitmap> photoTask =
|
||||
new AsyncTask<Long, Void, Bitmap>() {
|
||||
protected Bitmap doInBackground(Long... mMasterKeyId) {
|
||||
return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(), mMasterKeyId[0], true);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap photo) {
|
||||
@@ -846,11 +847,11 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
|
||||
// Note: order is important
|
||||
int color;
|
||||
if (isRevoked) {
|
||||
if (mIsRevoked) {
|
||||
mStatusText.setText(R.string.view_key_revoked);
|
||||
mStatusImage.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
|
||||
KeyFormattingUtils.STATE_REVOKED, R.color.icons, true);
|
||||
State.REVOKED, R.color.icons, true);
|
||||
color = getResources().getColor(R.color.android_red_light);
|
||||
|
||||
mActionEncryptFile.setVisibility(View.GONE);
|
||||
@@ -858,7 +859,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
mActionNfc.setVisibility(View.GONE);
|
||||
mFab.setVisibility(View.GONE);
|
||||
mQrCodeLayout.setVisibility(View.GONE);
|
||||
} else if (isExpired) {
|
||||
} else if (mIsExpired) {
|
||||
if (mIsSecret) {
|
||||
mStatusText.setText(R.string.view_key_expired_secret);
|
||||
} else {
|
||||
@@ -866,7 +867,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
}
|
||||
mStatusImage.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
|
||||
KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true);
|
||||
State.EXPIRED, R.color.icons, true);
|
||||
color = getResources().getColor(R.color.android_red_light);
|
||||
|
||||
mActionEncryptFile.setVisibility(View.GONE);
|
||||
@@ -879,10 +880,10 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
mStatusImage.setVisibility(View.GONE);
|
||||
color = getResources().getColor(R.color.primary);
|
||||
// reload qr code only if the fingerprint changed
|
||||
if ( !mFingerprint.equals(oldFingerprint)) {
|
||||
if (!mFingerprint.equals(oldFingerprint)) {
|
||||
loadQrCode(mFingerprint);
|
||||
}
|
||||
photoTask.execute(mFingerprint);
|
||||
photoTask.execute(mMasterKeyId);
|
||||
mQrCodeLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
// and place leftOf qr code
|
||||
@@ -926,16 +927,16 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
mStatusText.setText(R.string.view_key_verified);
|
||||
mStatusImage.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
|
||||
KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true);
|
||||
State.VERIFIED, R.color.icons, true);
|
||||
color = getResources().getColor(R.color.primary);
|
||||
photoTask.execute(mFingerprint);
|
||||
photoTask.execute(mMasterKeyId);
|
||||
|
||||
mFab.setVisibility(View.GONE);
|
||||
} else {
|
||||
mStatusText.setText(R.string.view_key_unverified);
|
||||
mStatusImage.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
|
||||
KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons, true);
|
||||
State.UNVERIFIED, R.color.icons, true);
|
||||
color = getResources().getColor(R.color.android_orange_light);
|
||||
|
||||
mFab.setVisibility(View.VISIBLE);
|
||||
@@ -943,27 +944,21 @@ public class ViewKeyActivity extends BaseActivity implements
|
||||
}
|
||||
|
||||
if (mPreviousColor == 0 || mPreviousColor == color) {
|
||||
mToolbar.setBackgroundColor(color);
|
||||
mStatusBar.setBackgroundColor(color);
|
||||
mBigToolbar.setBackgroundColor(color);
|
||||
mPreviousColor = color;
|
||||
} else {
|
||||
ObjectAnimator colorFade1 =
|
||||
ObjectAnimator.ofObject(mToolbar, "backgroundColor",
|
||||
new ArgbEvaluator(), mPreviousColor, color);
|
||||
ObjectAnimator colorFade2 =
|
||||
ObjectAnimator.ofObject(mStatusBar, "backgroundColor",
|
||||
new ArgbEvaluator(), mPreviousColor, color);
|
||||
ObjectAnimator colorFade3 =
|
||||
ObjectAnimator colorFade2 =
|
||||
ObjectAnimator.ofObject(mBigToolbar, "backgroundColor",
|
||||
new ArgbEvaluator(), mPreviousColor, color);
|
||||
|
||||
colorFade1.setDuration(1200);
|
||||
colorFade2.setDuration(1200);
|
||||
colorFade3.setDuration(1200);
|
||||
colorFade1.start();
|
||||
colorFade2.start();
|
||||
colorFade3.start();
|
||||
mPreviousColor = color;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ViewKeyAdvActivity extends BaseActivity implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
@@ -159,7 +157,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements
|
||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||
KeychainContract.KeyRings.USER_ID,
|
||||
KeychainContract.KeyRings.IS_REVOKED,
|
||||
KeychainContract.KeyRings.EXPIRY,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.VERIFIED,
|
||||
KeychainContract.KeyRings.HAS_ANY_SECRET
|
||||
};
|
||||
@@ -167,7 +165,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements
|
||||
static final int INDEX_MASTER_KEY_ID = 1;
|
||||
static final int INDEX_USER_ID = 2;
|
||||
static final int INDEX_IS_REVOKED = 3;
|
||||
static final int INDEX_EXPIRY = 4;
|
||||
static final int INDEX_IS_EXPIRED = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
|
||||
@@ -212,8 +210,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements
|
||||
|
||||
boolean isSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = !data.isNull(INDEX_EXPIRY)
|
||||
&& new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date());
|
||||
boolean isExpired = data.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isVerified = data.getInt(INDEX_VERIFIED) > 0;
|
||||
|
||||
// Note: order is important
|
||||
|
||||
@@ -260,7 +260,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
||||
static final String[] UNIFIED_PROJECTION = new String[]{
|
||||
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
||||
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
|
||||
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED,
|
||||
|
||||
};
|
||||
static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
|
||||
@@ -270,7 +270,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
||||
static final int INDEX_UNIFIED_ALGORITHM = 5;
|
||||
static final int INDEX_UNIFIED_KEY_SIZE = 6;
|
||||
static final int INDEX_UNIFIED_CREATION = 7;
|
||||
static final int INDEX_UNIFIED_EXPIRY = 8;
|
||||
static final int INDEX_UNIFIED_ID_EXPIRED = 8;
|
||||
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
setContentShown(false);
|
||||
|
||||
@@ -114,12 +114,12 @@ public class ViewKeyAdvUserIdsFragment extends LoaderFragment implements
|
||||
|
||||
static final String[] UNIFIED_PROJECTION = new String[]{
|
||||
KeyRings._ID, KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT
|
||||
KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.IS_EXPIRED, KeyRings.HAS_ENCRYPT
|
||||
};
|
||||
static final int INDEX_UNIFIED_MASTER_KEY_ID = 1;
|
||||
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
|
||||
static final int INDEX_UNIFIED_IS_REVOKED = 3;
|
||||
static final int INDEX_UNIFIED_EXPIRY = 4;
|
||||
static final int INDEX_UNIFIED_IS_EXPIRED = 4;
|
||||
static final int INDEX_UNIFIED_HAS_ENCRYPT = 5;
|
||||
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
|
||||
@@ -115,12 +115,12 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
||||
}
|
||||
|
||||
static final String[] TRUST_PROJECTION = new String[]{
|
||||
KeyRings._ID, KeyRings.FINGERPRINT, KeyRings.IS_REVOKED, KeyRings.EXPIRY,
|
||||
KeyRings._ID, KeyRings.FINGERPRINT, KeyRings.IS_REVOKED, KeyRings.IS_EXPIRED,
|
||||
KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED
|
||||
};
|
||||
static final int INDEX_TRUST_FINGERPRINT = 1;
|
||||
static final int INDEX_TRUST_IS_REVOKED = 2;
|
||||
static final int INDEX_TRUST_EXPIRY = 3;
|
||||
static final int INDEX_TRUST_IS_EXPIRED = 3;
|
||||
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
|
||||
@@ -169,8 +169,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
||||
|
||||
nothingSpecial = false;
|
||||
} else {
|
||||
Date expiryDate = new Date(data.getLong(INDEX_TRUST_EXPIRY) * 1000);
|
||||
if (!data.isNull(INDEX_TRUST_EXPIRY) && expiryDate.before(new Date())) {
|
||||
if (data.getInt(INDEX_TRUST_IS_EXPIRED) != 0) {
|
||||
|
||||
// if expired, don’t trust it!
|
||||
message.append(getString(R.string.key_trust_expired)).
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -175,9 +176,9 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
|
||||
}
|
||||
|
||||
if (entry.isRevoked()) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.REVOKED, R.color.bg_gray);
|
||||
} else if (entry.isExpired()) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.EXPIRED, R.color.bg_gray);
|
||||
}
|
||||
|
||||
if (entry.isRevoked() || entry.isExpired()) {
|
||||
|
||||
@@ -39,9 +39,9 @@ import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
||||
import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.ui.ViewKeyFragment;
|
||||
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.WeakHashMap;
|
||||
@@ -66,15 +66,15 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
|
||||
switch (isVerified) {
|
||||
case Certs.VERIFIED_SECRET:
|
||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||
null, KeyFormattingUtils.STATE_VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
case Certs.VERIFIED_SELF:
|
||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||
null, KeyFormattingUtils.STATE_UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
default:
|
||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||
null, KeyFormattingUtils.STATE_INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
|
||||
/**
|
||||
@@ -133,11 +134,11 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
|
||||
boolean enabled;
|
||||
if (cursor.getInt(mIndexIsRevoked) != 0) {
|
||||
h.statusIcon.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.REVOKED, R.color.bg_gray);
|
||||
enabled = false;
|
||||
} else if (cursor.getInt(mIndexIsExpiry) != 0) {
|
||||
h.statusIcon.setVisibility(View.VISIBLE);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.EXPIRED, R.color.bg_gray);
|
||||
enabled = false;
|
||||
} else {
|
||||
h.statusIcon.setVisibility(View.GONE);
|
||||
|
||||
@@ -272,12 +272,12 @@ public class SubkeysAdapter extends CursorAdapter {
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
|
||||
if (isRevoked) {
|
||||
vStatus.setImageResource(R.drawable.status_signature_revoked_cutout_24px);
|
||||
vStatus.setImageResource(R.drawable.status_signature_revoked_cutout_24dp);
|
||||
vStatus.setColorFilter(
|
||||
mContext.getResources().getColor(R.color.bg_gray),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else if (isExpired) {
|
||||
vStatus.setImageResource(R.drawable.status_signature_expired_cutout_24px);
|
||||
vStatus.setImageResource(R.drawable.status_signature_expired_cutout_24dp);
|
||||
vStatus.setColorFilter(
|
||||
mContext.getResources().getColor(R.color.bg_gray),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
public class UserIdsAdapter extends UserAttributesAdapter {
|
||||
protected LayoutInflater mInflater;
|
||||
@@ -127,7 +128,7 @@ public class UserIdsAdapter extends UserAttributesAdapter {
|
||||
|
||||
if (isRevoked) {
|
||||
// set revocation icon (can this even be primary?)
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.REVOKED, R.color.bg_gray);
|
||||
|
||||
// disable revoked user ids
|
||||
vName.setEnabled(false);
|
||||
@@ -149,13 +150,13 @@ public class UserIdsAdapter extends UserAttributesAdapter {
|
||||
int isVerified = cursor.getInt(INDEX_VERIFIED);
|
||||
switch (isVerified) {
|
||||
case Certs.VERIFIED_SECRET:
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
case Certs.VERIFIED_SELF:
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
default:
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -73,10 +72,8 @@ public class UserIdsAddedAdapter extends ArrayAdapter<String> {
|
||||
holder.vDelete.setVisibility(View.VISIBLE); // always visible
|
||||
|
||||
// not used:
|
||||
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.user_id_item_check_box);
|
||||
View certifiedLayout = convertView.findViewById(R.id.user_id_item_certified_layout);
|
||||
ImageView editImage = (ImageView) convertView.findViewById(R.id.user_id_item_edit_image);
|
||||
checkBox.setVisibility(View.GONE);
|
||||
certifiedLayout.setVisibility(View.GONE);
|
||||
editImage.setVisibility(View.GONE);
|
||||
|
||||
|
||||
@@ -137,12 +137,10 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
||||
}
|
||||
});
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
// date picker works based on default time zone
|
||||
Calendar minDateCal = Calendar.getInstance(TimeZone.getDefault());
|
||||
minDateCal.add(Calendar.DAY_OF_YEAR, 1); // at least one day after creation (today)
|
||||
mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
|
||||
}
|
||||
// date picker works based on default time zone
|
||||
Calendar minDateCal = Calendar.getInstance(TimeZone.getDefault());
|
||||
minDateCal.add(Calendar.DAY_OF_YEAR, 1); // at least one day after creation (today)
|
||||
mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
|
||||
|
||||
{
|
||||
ArrayList<Choice<Algorithm>> choices = new ArrayList<>();
|
||||
@@ -283,7 +281,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
||||
// For EC keys, add a curve
|
||||
if (algorithm == Algorithm.ECDH || algorithm == Algorithm.ECDSA) {
|
||||
curve = ((Choice<Curve>) mCurveSpinner.getSelectedItem()).getId();
|
||||
// Otherwise, get a keysize
|
||||
// Otherwise, get a keysize
|
||||
} else {
|
||||
keySize = getProperKeyLength(algorithm, getSelectedKeyLength());
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 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.dialog;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
|
||||
@@ -62,12 +62,9 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
||||
|
||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||
|
||||
|
||||
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||
alert.setTitle(R.string.warning);
|
||||
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFilename));
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
alert.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
|
||||
@@ -83,8 +83,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
|
||||
mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage);
|
||||
|
||||
builder.setTitle(R.string.warning);
|
||||
|
||||
final boolean hasSecret;
|
||||
|
||||
// If only a single key has been selected
|
||||
@@ -110,12 +108,14 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
}
|
||||
hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;
|
||||
|
||||
// Set message depending on which key it is.
|
||||
mMainMessage.setText(getString(
|
||||
hasSecret ? R.string.secret_key_deletion_confirmation
|
||||
: R.string.public_key_deletetion_confirmation,
|
||||
name
|
||||
));
|
||||
if (hasSecret) {
|
||||
// show title only for secret key deletions,
|
||||
// see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
|
||||
builder.setTitle(getString(R.string.title_delete_secret_key, name));
|
||||
mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name));
|
||||
} else {
|
||||
mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
|
||||
}
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
dismiss();
|
||||
return null;
|
||||
@@ -125,7 +125,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
||||
hasSecret = false;
|
||||
}
|
||||
|
||||
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
@@ -25,11 +25,14 @@ import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -97,62 +100,63 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
|
||||
|
||||
final CheckBox noExpiry = (CheckBox) view.findViewById(R.id.edit_subkey_expiry_no_expiry);
|
||||
final DatePicker datePicker = (DatePicker) view.findViewById(R.id.edit_subkey_expiry_date_picker);
|
||||
final TextView currentExpiry = (TextView) view.findViewById(R.id.edit_subkey_expiry_current_expiry);
|
||||
final LinearLayout expiryLayout = (LinearLayout) view.findViewById(R.id.edit_subkey_expiry_layout);
|
||||
|
||||
noExpiry.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
datePicker.setVisibility(View.GONE);
|
||||
expiryLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
datePicker.setVisibility(View.VISIBLE);
|
||||
expiryLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// init date picker with default selected date
|
||||
if (expiry == 0L) {
|
||||
noExpiry.setChecked(true);
|
||||
datePicker.setVisibility(View.GONE);
|
||||
expiryLayout.setVisibility(View.GONE);
|
||||
|
||||
Calendar todayCal = Calendar.getInstance(TimeZone.getDefault());
|
||||
if (creationCal.after(todayCal)) {
|
||||
// Note: This is just for the rare cases where creation is _after_ today
|
||||
|
||||
// set it to creation date +1 day (don't set it to creationCal, it would break crash
|
||||
// datePicker.setMinDate() execution with IllegalArgumentException
|
||||
Calendar creationCalPlusOne = (Calendar) creationCal.clone();
|
||||
creationCalPlusOne.add(Calendar.DAY_OF_YEAR, 1);
|
||||
datePicker.init(
|
||||
creationCalPlusOne.get(Calendar.YEAR),
|
||||
creationCalPlusOne.get(Calendar.MONTH),
|
||||
creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
|
||||
null
|
||||
);
|
||||
|
||||
} else {
|
||||
// normally, just init with today
|
||||
datePicker.init(
|
||||
todayCal.get(Calendar.YEAR),
|
||||
todayCal.get(Calendar.MONTH),
|
||||
todayCal.get(Calendar.DAY_OF_MONTH),
|
||||
null
|
||||
);
|
||||
}
|
||||
currentExpiry.setText(R.string.btn_no_date);
|
||||
} else {
|
||||
noExpiry.setChecked(false);
|
||||
datePicker.setVisibility(View.VISIBLE);
|
||||
expiryLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
// set date picker to current expiry
|
||||
datePicker.init(
|
||||
expiryCal.get(Calendar.YEAR),
|
||||
expiryCal.get(Calendar.MONTH),
|
||||
expiryCal.get(Calendar.DAY_OF_MONTH),
|
||||
null
|
||||
);
|
||||
// convert from UTC to time zone of device
|
||||
Calendar expiryCalTimeZone = (Calendar) expiryCal.clone();
|
||||
expiryCalTimeZone.setTimeZone(TimeZone.getDefault());
|
||||
currentExpiry.setText(DateFormat.getDateFormat(
|
||||
getActivity()).format(expiryCalTimeZone.getTime()));
|
||||
}
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
datePicker.setMinDate(creationCal.getTime().getTime());
|
||||
// date picker works based on default time zone
|
||||
Calendar todayCal = Calendar.getInstance(TimeZone.getDefault());
|
||||
if (creationCal.after(todayCal)) {
|
||||
// NOTE: This is just for the rare cases where creation is _after_ today
|
||||
// Min Date: Creation date + 1 day
|
||||
|
||||
Calendar creationCalPlusOne = (Calendar) creationCal.clone();
|
||||
creationCalPlusOne.add(Calendar.DAY_OF_YEAR, 1);
|
||||
datePicker.setMinDate(creationCalPlusOne.getTime().getTime());
|
||||
datePicker.init(
|
||||
creationCalPlusOne.get(Calendar.YEAR),
|
||||
creationCalPlusOne.get(Calendar.MONTH),
|
||||
creationCalPlusOne.get(Calendar.DAY_OF_MONTH),
|
||||
null
|
||||
);
|
||||
} else {
|
||||
// Min Date: today + 1 day
|
||||
|
||||
// at least one day after creation (today)
|
||||
todayCal.add(Calendar.DAY_OF_YEAR, 1);
|
||||
datePicker.setMinDate(todayCal.getTime().getTime());
|
||||
datePicker.init(
|
||||
todayCal.get(Calendar.YEAR),
|
||||
todayCal.get(Calendar.MONTH),
|
||||
todayCal.get(Calendar.DAY_OF_MONTH),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
|
||||
@@ -92,7 +92,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||
|
||||
alert.setTitle(title);
|
||||
alert.setMessage(R.string.enter_passphrase_twice);
|
||||
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null);
|
||||
|
||||
@@ -162,17 +162,17 @@ public class LinkedIdCreateDnsStep2Fragment extends Fragment {
|
||||
mVerifyImage.setVisibility(on ? View.GONE : View.VISIBLE);
|
||||
if (success == null) {
|
||||
mVerifyStatus.setText(R.string.linked_verifying);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else if (success) {
|
||||
mVerifyStatus.setText(R.string.linked_verify_success);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_green_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mVerifyStatus.setText(R.string.linked_verify_error);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_red_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
@@ -165,17 +165,17 @@ public class LinkedIdCreateHttpsStep2Fragment extends Fragment {
|
||||
mVerifyImage.setVisibility(on ? View.GONE : View.VISIBLE);
|
||||
if (success == null) {
|
||||
mVerifyStatus.setText(R.string.linked_verifying);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else if (success) {
|
||||
mVerifyStatus.setText(R.string.linked_verify_success);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_green_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mVerifyStatus.setText(R.string.linked_verify_error);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_red_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
@@ -144,17 +144,17 @@ public class LinkedIdCreateTwitterStep3Fragment extends Fragment {
|
||||
mVerifyImage.setVisibility(on ? View.GONE : View.VISIBLE);
|
||||
if (success == null) {
|
||||
mVerifyStatus.setText(R.string.linked_verifying);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else if (success) {
|
||||
mVerifyStatus.setText(R.string.linked_verify_success);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_green_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mVerifyStatus.setText(R.string.linked_verify_error);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24px);
|
||||
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout_24dp);
|
||||
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_red_dark),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
@@ -379,27 +379,29 @@ public class KeyFormattingUtils {
|
||||
|
||||
public static final int DEFAULT_COLOR = -1;
|
||||
|
||||
public static final int STATE_REVOKED = 1;
|
||||
public static final int STATE_EXPIRED = 2;
|
||||
public static final int STATE_VERIFIED = 3;
|
||||
public static final int STATE_UNAVAILABLE = 4;
|
||||
public static final int STATE_ENCRYPTED = 5;
|
||||
public static final int STATE_NOT_ENCRYPTED = 6;
|
||||
public static final int STATE_UNVERIFIED = 7;
|
||||
public static final int STATE_UNKNOWN_KEY = 8;
|
||||
public static final int STATE_INVALID = 9;
|
||||
public static final int STATE_NOT_SIGNED = 10;
|
||||
public static enum State {
|
||||
REVOKED,
|
||||
EXPIRED,
|
||||
VERIFIED,
|
||||
UNAVAILABLE,
|
||||
ENCRYPTED,
|
||||
NOT_ENCRYPTED,
|
||||
UNVERIFIED,
|
||||
UNKNOWN_KEY,
|
||||
INVALID,
|
||||
NOT_SIGNED
|
||||
}
|
||||
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, int state) {
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, State state) {
|
||||
setStatusImage(context, statusIcon, null, state);
|
||||
}
|
||||
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, int state) {
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, State state) {
|
||||
setStatusImage(context, statusIcon, statusText, state, KeyFormattingUtils.DEFAULT_COLOR, false);
|
||||
}
|
||||
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText,
|
||||
int state, int color) {
|
||||
State state, int color) {
|
||||
setStatusImage(context, statusIcon, statusText, state, color, false);
|
||||
}
|
||||
|
||||
@@ -407,16 +409,16 @@ public class KeyFormattingUtils {
|
||||
* Sets status image based on constant
|
||||
*/
|
||||
public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText,
|
||||
int state, int color, boolean big) {
|
||||
State state, int color, boolean big) {
|
||||
switch (state) {
|
||||
/** GREEN: everything is good **/
|
||||
case STATE_VERIFIED: {
|
||||
case VERIFIED: {
|
||||
if (big) {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_96px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_96dp));
|
||||
} else {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_24dp));
|
||||
}
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_green_light;
|
||||
@@ -428,9 +430,9 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ENCRYPTED: {
|
||||
case ENCRYPTED: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_lock_closed_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_lock_closed_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_green_light;
|
||||
}
|
||||
@@ -442,13 +444,13 @@ public class KeyFormattingUtils {
|
||||
break;
|
||||
}
|
||||
/** ORANGE: mostly bad... **/
|
||||
case STATE_UNVERIFIED: {
|
||||
case UNVERIFIED: {
|
||||
if (big) {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_96px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_96dp));
|
||||
} else {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_24dp));
|
||||
}
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_orange_light;
|
||||
@@ -460,9 +462,9 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_UNKNOWN_KEY: {
|
||||
case UNKNOWN_KEY: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_orange_light;
|
||||
}
|
||||
@@ -474,13 +476,13 @@ public class KeyFormattingUtils {
|
||||
break;
|
||||
}
|
||||
/** RED: really bad... **/
|
||||
case STATE_REVOKED: {
|
||||
case REVOKED: {
|
||||
if (big) {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_96px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_96dp));
|
||||
} else {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_24dp));
|
||||
}
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_red_light;
|
||||
@@ -492,13 +494,13 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_EXPIRED: {
|
||||
case EXPIRED: {
|
||||
if (big) {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_96px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_96dp));
|
||||
} else {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_24dp));
|
||||
}
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_red_light;
|
||||
@@ -510,9 +512,9 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_NOT_ENCRYPTED: {
|
||||
case NOT_ENCRYPTED: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_lock_open_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_lock_open_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_red_light;
|
||||
}
|
||||
@@ -523,9 +525,9 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_NOT_SIGNED: {
|
||||
case NOT_SIGNED: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_red_light;
|
||||
}
|
||||
@@ -536,9 +538,9 @@ public class KeyFormattingUtils {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_INVALID: {
|
||||
case INVALID: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.android_red_light;
|
||||
}
|
||||
@@ -550,9 +552,9 @@ public class KeyFormattingUtils {
|
||||
break;
|
||||
}
|
||||
/** special **/
|
||||
case STATE_UNAVAILABLE: {
|
||||
case UNAVAILABLE: {
|
||||
statusIcon.setImageDrawable(
|
||||
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24px));
|
||||
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24dp));
|
||||
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
|
||||
color = R.color.bg_gray;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
public class CertifyKeySpinner extends KeySpinner {
|
||||
private long mHiddenMasterKeyId = Constants.key.none;
|
||||
@@ -103,16 +104,16 @@ public class CertifyKeySpinner extends KeySpinner {
|
||||
@Override
|
||||
boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
|
||||
if (cursor.getInt(mIndexIsRevoked) != 0) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.REVOKED, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
if (cursor.getInt(mIndexIsExpired) != 0) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.EXPIRED, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
// don't invalidate the "None" entry, which is also null!
|
||||
if (cursor.getPosition() != 0 && cursor.isNull(mIndexHasCertify)) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.UNAVAILABLE, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
}
|
||||
|
||||
private void setImageByKey(ImageView view, EncryptionKey key) {
|
||||
Bitmap photo = ContactHelper.photoFromFingerprint(getContext().getContentResolver(), key.getFingerprint());
|
||||
Bitmap photo = ContactHelper.getCachedPhotoByMasterKeyId(getContext().getContentResolver(), key.getKeyId());
|
||||
|
||||
if (photo != null) {
|
||||
view.setImageBitmap(photo);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.widget.ImageView;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
public class SignKeySpinner extends KeySpinner {
|
||||
public SignKeySpinner(Context context) {
|
||||
@@ -84,15 +85,15 @@ public class SignKeySpinner extends KeySpinner {
|
||||
@Override
|
||||
boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
|
||||
if (cursor.getInt(mIndexIsRevoked) != 0) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.REVOKED, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
if (cursor.getInt(mIndexIsExpired) != 0) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.EXPIRED, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
if (cursor.getInt(mIndexHasSign) == 0) {
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, R.color.bg_gray);
|
||||
KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.UNAVAILABLE, R.color.bg_gray);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -50,40 +49,7 @@ import java.util.Set;
|
||||
|
||||
public class ContactHelper {
|
||||
|
||||
public static final String[] KEYS_TO_CONTACT_PROJECTION = new String[]{
|
||||
KeychainContract.KeyRings.USER_ID,
|
||||
KeychainContract.KeyRings.FINGERPRINT,
|
||||
KeychainContract.KeyRings.KEY_ID,
|
||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||
KeychainContract.KeyRings.EXPIRY,
|
||||
KeychainContract.KeyRings.IS_REVOKED};
|
||||
|
||||
public static final int INDEX_USER_ID = 0;
|
||||
public static final int INDEX_FINGERPRINT = 1;
|
||||
public static final int INDEX_KEY_ID = 2;
|
||||
public static final int INDEX_MASTER_KEY_ID = 3;
|
||||
public static final int INDEX_EXPIRY = 4;
|
||||
public static final int INDEX_IS_REVOKED = 5;
|
||||
|
||||
public static final String[] USER_IDS_PROJECTION = new String[]{
|
||||
UserPackets.USER_ID
|
||||
};
|
||||
|
||||
public static final int INDEX_USER_IDS_USER_ID = 0;
|
||||
|
||||
public static final String NON_REVOKED_SELECTION = UserPackets.IS_REVOKED + "=0";
|
||||
|
||||
public static final String[] ID_PROJECTION = new String[]{ContactsContract.RawContacts._ID};
|
||||
public static final String[] SOURCE_ID_PROJECTION = new String[]{ContactsContract.RawContacts.SOURCE_ID};
|
||||
|
||||
public static final String ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION =
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?";
|
||||
public static final String ACCOUNT_TYPE_SELECTION = ContactsContract.RawContacts.ACCOUNT_TYPE + "=?";
|
||||
public static final String RAW_CONTACT_AND_MIMETYPE_SELECTION =
|
||||
ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?";
|
||||
public static final String ID_SELECTION = ContactsContract.RawContacts._ID + "=?";
|
||||
|
||||
private static final Map<String, Bitmap> photoCache = new HashMap<>();
|
||||
private static final Map<Long, Bitmap> photoCache = new HashMap<>();
|
||||
|
||||
public static List<String> getPossibleUserEmails(Context context) {
|
||||
Set<String> accountMails = getAccountEmails(context);
|
||||
@@ -125,33 +91,33 @@ public class ContactHelper {
|
||||
* @return
|
||||
*/
|
||||
private static Set<String> getContactNamesFromEmails(Context context, Set<String> emails) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
Set<String> names = new HashSet<>();
|
||||
for (String email : emails) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
new String[]{ContactsContract.CommonDataKinds.Email.ADDRESS,
|
||||
ContactsContract.Contacts.DISPLAY_NAME},
|
||||
ContactsContract.CommonDataKinds.Email.ADDRESS + "=?",
|
||||
new String[]{email}, null
|
||||
);
|
||||
if (profileCursor == null) return null;
|
||||
|
||||
Set<String> currNames = new HashSet<>();
|
||||
while (profileCursor.moveToNext()) {
|
||||
String name = profileCursor.getString(1);
|
||||
if (name != null) {
|
||||
currNames.add(name);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
names.addAll(currNames);
|
||||
Set<String> names = new HashSet<>();
|
||||
for (String email : emails) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.CommonDataKinds.Email.ADDRESS,
|
||||
ContactsContract.Contacts.DISPLAY_NAME
|
||||
},
|
||||
ContactsContract.CommonDataKinds.Email.ADDRESS + "=?",
|
||||
new String[]{email}, null
|
||||
);
|
||||
if (profileCursor == null) {
|
||||
return null;
|
||||
}
|
||||
return names;
|
||||
} else {
|
||||
return new HashSet<>();
|
||||
|
||||
Set<String> currNames = new HashSet<>();
|
||||
while (profileCursor.moveToNext()) {
|
||||
String name = profileCursor.getString(1);
|
||||
if (name != null) {
|
||||
currNames.add(name);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
names.addAll(currNames);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,38 +128,37 @@ public class ContactHelper {
|
||||
* @return
|
||||
*/
|
||||
private static Set<String> getMainProfileContactEmails(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
Uri.withAppendedPath(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
|
||||
new String[]{ContactsContract.CommonDataKinds.Email.ADDRESS,
|
||||
ContactsContract.CommonDataKinds.Email.IS_PRIMARY},
|
||||
|
||||
// Selects only email addresses
|
||||
ContactsContract.Contacts.Data.MIMETYPE + "=?",
|
||||
new String[]{
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
|
||||
},
|
||||
// Show primary rows first. Note that there won't be a primary email address if the
|
||||
// user hasn't specified one.
|
||||
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"
|
||||
);
|
||||
if (profileCursor == null) return null;
|
||||
|
||||
Set<String> emails = new HashSet<>();
|
||||
while (profileCursor.moveToNext()) {
|
||||
String email = profileCursor.getString(0);
|
||||
if (email != null) {
|
||||
emails.add(email);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
return emails;
|
||||
} else {
|
||||
return new HashSet<>();
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
Uri.withAppendedPath(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
|
||||
new String[]{
|
||||
ContactsContract.CommonDataKinds.Email.ADDRESS,
|
||||
ContactsContract.CommonDataKinds.Email.IS_PRIMARY
|
||||
},
|
||||
// Selects only email addresses
|
||||
ContactsContract.Contacts.Data.MIMETYPE + "=?",
|
||||
new String[]{
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
|
||||
},
|
||||
// Show primary rows first. Note that there won't be a primary email address if the
|
||||
// user hasn't specified one.
|
||||
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"
|
||||
);
|
||||
if (profileCursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> emails = new HashSet<>();
|
||||
while (profileCursor.moveToNext()) {
|
||||
String email = profileCursor.getString(0);
|
||||
if (email != null) {
|
||||
emails.add(email);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
return emails;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,26 +169,27 @@ public class ContactHelper {
|
||||
* @return
|
||||
*/
|
||||
private static List<String> getMainProfileContactName(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(ContactsContract.Profile.CONTENT_URI,
|
||||
new String[]{ContactsContract.Profile.DISPLAY_NAME},
|
||||
null, null, null);
|
||||
if (profileCursor == null) return null;
|
||||
|
||||
Set<String> names = new HashSet<>();
|
||||
// should only contain one entry!
|
||||
while (profileCursor.moveToNext()) {
|
||||
String name = profileCursor.getString(0);
|
||||
if (name != null) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
return new ArrayList<>(names);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor profileCursor = resolver.query(
|
||||
ContactsContract.Profile.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.Profile.DISPLAY_NAME
|
||||
},
|
||||
null, null, null);
|
||||
if (profileCursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> names = new HashSet<>();
|
||||
// should only contain one entry!
|
||||
while (profileCursor.moveToNext()) {
|
||||
String name = profileCursor.getString(0);
|
||||
if (name != null) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
profileCursor.close();
|
||||
return new ArrayList<>(names);
|
||||
}
|
||||
|
||||
public static List<String> getContactMails(Context context) {
|
||||
@@ -231,7 +197,9 @@ public class ContactHelper {
|
||||
Cursor mailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
new String[]{ContactsContract.CommonDataKinds.Email.DATA},
|
||||
null, null, null);
|
||||
if (mailCursor == null) return new ArrayList<>();
|
||||
if (mailCursor == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Set<String> mails = new HashSet<>();
|
||||
while (mailCursor.moveToNext()) {
|
||||
@@ -249,7 +217,9 @@ public class ContactHelper {
|
||||
Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,
|
||||
new String[]{ContactsContract.Contacts.DISPLAY_NAME},
|
||||
null, null, null);
|
||||
if (cursor == null) return new ArrayList<>();
|
||||
if (cursor == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Set<String> names = new HashSet<>();
|
||||
while (cursor.moveToNext()) {
|
||||
@@ -275,72 +245,111 @@ public class ContactHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bitmap photoFromFingerprint(ContentResolver contentResolver, String fingerprint) {
|
||||
if (fingerprint == null) return null;
|
||||
if (!photoCache.containsKey(fingerprint)) {
|
||||
photoCache.put(fingerprint, loadPhotoFromFingerprint(contentResolver, fingerprint));
|
||||
public static Bitmap getCachedPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId) {
|
||||
if (masterKeyId == -1) {
|
||||
return null;
|
||||
}
|
||||
return photoCache.get(fingerprint);
|
||||
if (!photoCache.containsKey(masterKeyId)) {
|
||||
photoCache.put(masterKeyId, loadPhotoByMasterKeyId(contentResolver, masterKeyId, false));
|
||||
}
|
||||
return photoCache.get(masterKeyId);
|
||||
}
|
||||
|
||||
private static Bitmap loadPhotoFromFingerprint(ContentResolver contentResolver, String fingerprint) {
|
||||
if (fingerprint == null) return null;
|
||||
public static Bitmap loadPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId,
|
||||
boolean highRes) {
|
||||
if (masterKeyId == -1) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
int rawContactId = findRawContactId(contentResolver, fingerprint);
|
||||
if (rawContactId == -1) return null;
|
||||
long rawContactId = findRawContactId(contentResolver, masterKeyId);
|
||||
if (rawContactId == -1) {
|
||||
return null;
|
||||
}
|
||||
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
|
||||
Uri contactUri = ContactsContract.RawContacts.getContactLookupUri(contentResolver, rawContactUri);
|
||||
InputStream photoInputStream =
|
||||
ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri);
|
||||
if (photoInputStream == null) return null;
|
||||
ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri, highRes);
|
||||
if (photoInputStream == null) {
|
||||
return null;
|
||||
}
|
||||
return BitmapFactory.decodeStream(photoInputStream);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String[] KEYS_TO_CONTACT_PROJECTION = new String[]{
|
||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||
KeychainContract.KeyRings.USER_ID,
|
||||
KeychainContract.KeyRings.IS_EXPIRED,
|
||||
KeychainContract.KeyRings.IS_REVOKED};
|
||||
|
||||
public static final int INDEX_MASTER_KEY_ID = 0;
|
||||
public static final int INDEX_USER_ID = 1;
|
||||
public static final int INDEX_IS_EXPIRED = 2;
|
||||
public static final int INDEX_IS_REVOKED = 3;
|
||||
|
||||
/**
|
||||
* Write the current Keychain to the contact db
|
||||
* Write/Update the current OpenKeychain keys to the contact db
|
||||
*/
|
||||
public static void writeKeysToContacts(Context context) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Set<String> contactFingerprints = getRawContactFingerprints(resolver);
|
||||
Set<Long> deletedKeys = getRawContactMasterKeyIds(resolver);
|
||||
|
||||
// debugDeleteRawContacts(resolver);
|
||||
|
||||
// ContentProviderClient client = resolver.acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
|
||||
// ContentValues values = new ContentValues();
|
||||
// Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
|
||||
// values.put(ContactsContract.Settings.ACCOUNT_NAME, account.name);
|
||||
// values.put(ContactsContract.Settings.ACCOUNT_TYPE, account.type);
|
||||
// values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, true);
|
||||
// try {
|
||||
// client.insert(ContactsContract.Settings.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(), values);
|
||||
// } catch (RemoteException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
// Load all Keys from OK
|
||||
Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), KEYS_TO_CONTACT_PROJECTION,
|
||||
null, null, null);
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
String[] primaryUserId = KeyRing.splitUserId(cursor.getString(INDEX_USER_ID));
|
||||
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(cursor.getBlob(INDEX_FINGERPRINT));
|
||||
contactFingerprints.remove(fingerprint);
|
||||
String keyIdShort = KeyFormattingUtils.convertKeyIdToHexShort(cursor.getLong(INDEX_KEY_ID));
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
|
||||
&& new Date(cursor.getLong(INDEX_EXPIRY) * 1000).before(new Date());
|
||||
String[] userIdSplit = KeyRing.splitUserId(cursor.getString(INDEX_USER_ID));
|
||||
String keyIdShort = KeyFormattingUtils.convertKeyIdToHexShort(cursor.getLong(INDEX_MASTER_KEY_ID));
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
int rawContactId = findRawContactId(resolver, fingerprint);
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
|
||||
|
||||
Log.d(Constants.TAG, "raw contact id: "+rawContactId);
|
||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
||||
|
||||
deletedKeys.remove(masterKeyId);
|
||||
|
||||
// get raw contact to this master key id
|
||||
long rawContactId = findRawContactId(resolver, masterKeyId);
|
||||
Log.d(Constants.TAG, "rawContactId: " + rawContactId);
|
||||
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
|
||||
|
||||
// Do not store expired or revoked keys in contact db - and remove them if they already exist
|
||||
if (isExpired || isRevoked) {
|
||||
Log.d(Constants.TAG, "Expired or revoked: Deleting " + rawContactId);
|
||||
if (rawContactId != -1) {
|
||||
resolver.delete(ContactsContract.RawContacts.CONTENT_URI, ID_SELECTION,
|
||||
new String[]{Integer.toString(rawContactId)});
|
||||
deleteRawContactById(resolver, rawContactId);
|
||||
}
|
||||
} else if (primaryUserId[0] != null) {
|
||||
} else if (userIdSplit[0] != null) {
|
||||
|
||||
// Create a new rawcontact with corresponding key if it does not exist yet
|
||||
if (rawContactId == -1) {
|
||||
insertContact(ops, context, fingerprint);
|
||||
Log.d(Constants.TAG, "Insert new raw contact with masterKeyId " + masterKeyId);
|
||||
|
||||
insertContact(ops, context, masterKeyId);
|
||||
writeContactKey(ops, context, rawContactId, masterKeyId, keyIdShort);
|
||||
}
|
||||
|
||||
// We always update the display name (which is derived from primary user id)
|
||||
// and email addresses from user id
|
||||
writeContactDisplayName(ops, rawContactId, primaryUserId[0]);
|
||||
writeContactDisplayName(ops, rawContactId, userIdSplit[0]);
|
||||
writeContactEmail(ops, resolver, rawContactId, masterKeyId);
|
||||
try {
|
||||
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
|
||||
@@ -352,43 +361,84 @@ public class ContactHelper {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Delete fingerprints that are no longer present in OK
|
||||
for (String fingerprint : contactFingerprints) {
|
||||
resolver.delete(ContactsContract.RawContacts.CONTENT_URI, ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION,
|
||||
new String[]{Constants.ACCOUNT_TYPE, fingerprint});
|
||||
// Delete master key ids that are no longer present in OK
|
||||
for (Long masterKeyId : deletedKeys) {
|
||||
Log.d(Constants.TAG, "Delete raw contact with masterKeyId " + masterKeyId);
|
||||
deleteRawContactByMasterKeyId(resolver, masterKeyId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a set of all key fingerprints currently present in the contact db
|
||||
* Delete all raw contacts associated to OpenKeychain.
|
||||
* <p/>
|
||||
* TODO: Does this work?
|
||||
*/
|
||||
private static Set<String> getRawContactFingerprints(ContentResolver resolver) {
|
||||
HashSet<String> result = new HashSet<>();
|
||||
Cursor fingerprints = resolver.query(ContactsContract.RawContacts.CONTENT_URI, SOURCE_ID_PROJECTION,
|
||||
ACCOUNT_TYPE_SELECTION, new String[]{Constants.ACCOUNT_TYPE}, null);
|
||||
if (fingerprints != null) {
|
||||
while (fingerprints.moveToNext()) {
|
||||
result.add(fingerprints.getString(0));
|
||||
private static int debugDeleteRawContacts(ContentResolver resolver) {
|
||||
Log.d(Constants.TAG, "Deleting all raw contacts associated to OK...");
|
||||
return resolver.delete(ContactsContract.RawContacts.CONTENT_URI,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE
|
||||
});
|
||||
}
|
||||
|
||||
private static int deleteRawContactById(ContentResolver resolver, long rawContactId) {
|
||||
return resolver.delete(ContactsContract.RawContacts.CONTENT_URI,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts._ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(rawContactId)
|
||||
});
|
||||
}
|
||||
|
||||
private static int deleteRawContactByMasterKeyId(ContentResolver resolver, long masterKeyId) {
|
||||
return resolver.delete(ContactsContract.RawContacts.CONTENT_URI,
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(masterKeyId)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a set of all key master key ids currently present in the contact db
|
||||
*/
|
||||
private static Set<Long> getRawContactMasterKeyIds(ContentResolver resolver) {
|
||||
HashSet<Long> result = new HashSet<>();
|
||||
Cursor masterKeyIds = resolver.query(ContactsContract.RawContacts.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.RawContacts.SOURCE_ID
|
||||
},
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE
|
||||
}, null);
|
||||
if (masterKeyIds != null) {
|
||||
while (masterKeyIds.moveToNext()) {
|
||||
result.add(masterKeyIds.getLong(0));
|
||||
}
|
||||
fingerprints.close();
|
||||
masterKeyIds.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will search the contact db for a raw contact with a given fingerprint
|
||||
* This will search the contact db for a raw contact with a given master key id
|
||||
*
|
||||
* @return raw contact id or -1 if not found
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
private static int findRawContactId(ContentResolver resolver, String fingerprint) {
|
||||
int rawContactId = -1;
|
||||
Cursor raw = resolver.query(ContactsContract.RawContacts.CONTENT_URI, ID_PROJECTION,
|
||||
ACCOUNT_TYPE_AND_SOURCE_ID_SELECTION, new String[]{Constants.ACCOUNT_TYPE, fingerprint}, null, null);
|
||||
private static long findRawContactId(ContentResolver resolver, long masterKeyId) {
|
||||
long rawContactId = -1;
|
||||
Cursor raw = resolver.query(ContactsContract.RawContacts.CONTENT_URI,
|
||||
new String[]{
|
||||
ContactsContract.RawContacts._ID
|
||||
},
|
||||
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?",
|
||||
new String[]{
|
||||
Constants.ACCOUNT_TYPE, Long.toString(masterKeyId)
|
||||
}, null, null);
|
||||
if (raw != null) {
|
||||
if (raw.moveToNext()) {
|
||||
rawContactId = raw.getInt(0);
|
||||
rawContactId = raw.getLong(0);
|
||||
}
|
||||
raw.close();
|
||||
}
|
||||
@@ -396,13 +446,13 @@ public class ContactHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a empty raw contact with a given fingerprint
|
||||
* Creates a empty raw contact with a given masterKeyId
|
||||
*/
|
||||
private static void insertContact(ArrayList<ContentProviderOperation> ops, Context context, String fingerprint) {
|
||||
private static void insertContact(ArrayList<ContentProviderOperation> ops, Context context, long masterKeyId) {
|
||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE)
|
||||
.withValue(ContactsContract.RawContacts.SOURCE_ID, fingerprint)
|
||||
.withValue(ContactsContract.RawContacts.SOURCE_ID, Long.toString(masterKeyId))
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -411,7 +461,7 @@ public class ContactHelper {
|
||||
* <p/>
|
||||
* This creates the link to OK in contact details
|
||||
*/
|
||||
private static void writeContactKey(ArrayList<ContentProviderOperation> ops, Context context, int rawContactId,
|
||||
private static void writeContactKey(ArrayList<ContentProviderOperation> ops, Context context, long rawContactId,
|
||||
long masterKeyId, String keyIdShort) {
|
||||
ops.add(referenceRawContact(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI), rawContactId)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, Constants.CUSTOM_CONTACT_DATA_MIME_TYPE)
|
||||
@@ -424,16 +474,22 @@ public class ContactHelper {
|
||||
* Write all known email addresses of a key (derived from user ids) to a given raw contact
|
||||
*/
|
||||
private static void writeContactEmail(ArrayList<ContentProviderOperation> ops, ContentResolver resolver,
|
||||
int rawContactId, long masterKeyId) {
|
||||
ops.add(selectByRawContactAndItemType(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI),
|
||||
long rawContactId, long masterKeyId) {
|
||||
ops.add(selectByRawContactAndItemType(
|
||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI),
|
||||
rawContactId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE).build());
|
||||
Cursor ids = resolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
||||
USER_IDS_PROJECTION, NON_REVOKED_SELECTION, null, null);
|
||||
new String[]{
|
||||
UserPackets.USER_ID
|
||||
},
|
||||
UserPackets.IS_REVOKED + "=0",
|
||||
null, null);
|
||||
if (ids != null) {
|
||||
while (ids.moveToNext()) {
|
||||
String[] userId = KeyRing.splitUserId(ids.getString(0));
|
||||
if (userId[1] != null) {
|
||||
ops.add(referenceRawContact(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI),
|
||||
ops.add(referenceRawContact(
|
||||
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI),
|
||||
rawContactId)
|
||||
.withValue(ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
||||
@@ -445,7 +501,7 @@ public class ContactHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeContactDisplayName(ArrayList<ContentProviderOperation> ops, int rawContactId,
|
||||
private static void writeContactDisplayName(ArrayList<ContentProviderOperation> ops, long rawContactId,
|
||||
String displayName) {
|
||||
if (displayName != null) {
|
||||
ops.add(insertOrUpdateForRawContact(ContactsContract.Data.CONTENT_URI, rawContactId,
|
||||
@@ -456,13 +512,13 @@ public class ContactHelper {
|
||||
}
|
||||
|
||||
private static ContentProviderOperation.Builder referenceRawContact(ContentProviderOperation.Builder builder,
|
||||
int rawContactId) {
|
||||
long rawContactId) {
|
||||
return rawContactId == -1 ?
|
||||
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) :
|
||||
builder.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
|
||||
}
|
||||
|
||||
private static ContentProviderOperation.Builder insertOrUpdateForRawContact(Uri uri, int rawContactId,
|
||||
private static ContentProviderOperation.Builder insertOrUpdateForRawContact(Uri uri, long rawContactId,
|
||||
String itemType) {
|
||||
if (rawContactId == -1) {
|
||||
return referenceRawContact(ContentProviderOperation.newInsert(uri), rawContactId).withValue(
|
||||
@@ -473,8 +529,11 @@ public class ContactHelper {
|
||||
}
|
||||
|
||||
private static ContentProviderOperation.Builder selectByRawContactAndItemType(
|
||||
ContentProviderOperation.Builder builder, int rawContactId, String itemType) {
|
||||
return builder.withSelection(RAW_CONTACT_AND_MIMETYPE_SELECTION,
|
||||
new String[]{Integer.toString(rawContactId), itemType});
|
||||
ContentProviderOperation.Builder builder, long rawContactId, String itemType) {
|
||||
return builder.withSelection(
|
||||
ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?",
|
||||
new String[]{
|
||||
Long.toString(rawContactId), itemType
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 641 B After Width: | Height: | Size: 669 B |
|
Before Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 381 B |
|
Before Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 884 B |
|
After Width: | Height: | Size: 524 B |
|
After Width: | Height: | Size: 651 B |
|
Before Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 556 B |
|
Before Width: | Height: | Size: 373 B |
|
Before Width: | Height: | Size: 458 B |
|
Before Width: | Height: | Size: 573 B |
|
Before Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 702 B |
|
Before Width: | Height: | Size: 394 B |
|
Before Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 953 B |
|
Before Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 356 B |
|
After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 309 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_close_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 416 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_search_24dp.png
Normal file
|
After Width: | Height: | Size: 726 B |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 325 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 248 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_done_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 276 B |
|
After Width: | Height: | Size: 262 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_folder_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 227 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 381 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_help_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 588 B |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 642 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_lock_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 409 B |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 351 B |
|
After Width: | Height: | Size: 394 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_person_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 301 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_save_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.png
Normal file
|
After Width: | Height: | Size: 341 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_search_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 522 B |
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 572 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_share_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 513 B |
|
After Width: | Height: | Size: 209 B |
BIN
OpenKeychain/src/main/res/drawable-hdpi/ic_warning_grey_24dp.png
Normal file
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |