diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2015-03-05 12:10:51 +0100 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2015-03-05 12:10:51 +0100 |
commit | 7b3bc4ca98c2be52bec996287c5997c3c52e3603 (patch) | |
tree | 861f5c7d329ea8c96e673b2c16f068d593a55fb9 /OpenKeychain/src/main/java/org | |
parent | 98ce06dbc9bea56d2960df2d7b8e7a5bc9e9e43a (diff) | |
parent | 8c8fdd6c495bb12f5c76c9d1fc4a6a44f1c3808b (diff) | |
download | open-keychain-7b3bc4ca98c2be52bec996287c5997c3c52e3603.tar.gz open-keychain-7b3bc4ca98c2be52bec996287c5997c3c52e3603.tar.bz2 open-keychain-7b3bc4ca98c2be52bec996287c5997c3c52e3603.zip |
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
Diffstat (limited to 'OpenKeychain/src/main/java/org')
38 files changed, 780 insertions, 451 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 67fa30a44..2d3ee6188 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -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"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 01f6735ea..a4dc12a37 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -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 - - //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 + // 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) { + } } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index ea4fedc56..a856a4fc3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -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> { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 1a251eb79..da0394573 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 62c38d136..60cc404b6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 6e0115342..920488e3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -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); } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java index 8aa9fa6db..ac74e87ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java @@ -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); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 8723c7255..7d8fd1388 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index 2eb35351e..cd6cdf4d6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -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, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index b56da463a..a44eef216 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index b655a7e55..138f2f4e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -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(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 53fd9cdfd..29621662f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index afec3bf06..65d7eca37 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -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; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 51dec767c..678ecd289 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index 9d79b377c..9390e8a69 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 8d0a2dd1d..95a6faea9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java index 492dfd0f7..ad437f924 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java @@ -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) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index 25edc7a02..d22f01a48 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -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)). diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 6ba9e26ad..429feb075 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -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()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java index a44358172..329b95ebc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index a836b35df..226fda20b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index ff5fbb49a..096dea51f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 3c4b0fedf..1cf3f4d38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -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; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java index 01218a4e4..970855c77 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java index d5376cbdc..0b1d39fc1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java @@ -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()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java index d405b1dda..794af5b15 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java @@ -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; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index 879e3f6da..07462b4ff 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -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) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 802f0c11b..32789d53b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -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) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java index f46e253c0..37e05a61d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java @@ -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); - - 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 - ); - } + expiryLayout.setVisibility(View.GONE); + + currentExpiry.setText(R.string.btn_no_date); } else { noExpiry.setChecked(false); - datePicker.setVisibility(View.VISIBLE); + expiryLayout.setVisibility(View.VISIBLE); + + // 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())); + } + + // 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 - // set date picker to current expiry + Calendar creationCalPlusOne = (Calendar) creationCal.clone(); + creationCalPlusOne.add(Calendar.DAY_OF_YEAR, 1); + datePicker.setMinDate(creationCalPlusOne.getTime().getTime()); datePicker.init( - expiryCal.get(Calendar.YEAR), - expiryCal.get(Calendar.MONTH), - expiryCal.get(Calendar.DAY_OF_MONTH), + creationCalPlusOne.get(Calendar.YEAR), + creationCalPlusOne.get(Calendar.MONTH), + creationCalPlusOne.get(Calendar.DAY_OF_MONTH), null ); - } + } else { + // Min Date: today + 1 day - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - datePicker.setMinDate(creationCal.getTime().getTime()); + // 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() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index a05719072..a3ffe250b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateDnsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateDnsStep2Fragment.java index 71a3673f2..3b0860fa9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateDnsStep2Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateDnsStep2Fragment.java @@ -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); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java index 78c7caf53..7d2f3dfdb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java @@ -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); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateTwitterStep3Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateTwitterStep3Fragment.java index f395807cf..d298e8251 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateTwitterStep3Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateTwitterStep3Fragment.java @@ -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); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index 38ed88b9c..c5403e054 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -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 void setStatusImage(Context context, ImageView statusIcon, int state) { + 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, 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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 6d0e6556f..fc912fccb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index f05f5f96b..d20e2bc99 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -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); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java index fe91e306e..10327a6a4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java @@ -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; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index 3cf201ed7..44bcc52a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -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); - } + 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); } - return names; - } else { - return new HashSet<>(); + 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; + 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); - } + 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<>(); } + 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; + 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); - } + 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<>(); } + 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); } + } + + /** + * Delete all raw contacts associated to OpenKeychain. + * <p/> + * TODO: Does this work? + */ + 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 fingerprints currently present in the contact db + * @return a set of all key master key ids currently present in the contact db */ - 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 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 + }); } } |