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 e409e1bc8..e32677c7a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -56,6 +56,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.KeyUpdateHelper; import org.sufficientlysecure.keychain.util.Preferences; @@ -572,16 +573,10 @@ public class KeyListFragment extends LoaderFragment // Note: order is important! if (isRevoked) { - h.mStatus.setImageDrawable( - getResources().getDrawable(R.drawable.status_signature_revoked_cutout)); - h.mStatus.setColorFilter(getResources().getColor(R.color.android_red_dark), - PorterDuff.Mode.SRC_ATOP); + KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, KeyFormattingUtils.STATE_REVOKED); h.mStatus.setVisibility(View.VISIBLE); } else if (isExpired) { - h.mStatus.setImageDrawable( - getResources().getDrawable(R.drawable.status_signature_expired_cutout)); - h.mStatus.setColorFilter(getResources().getColor(R.color.android_orange_dark), - PorterDuff.Mode.SRC_ATOP); + KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, KeyFormattingUtils.STATE_EXPIRED); h.mStatus.setVisibility(View.VISIBLE); } else if (isVerified) { if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) { @@ -589,10 +584,7 @@ public class KeyListFragment extends LoaderFragment h.mStatus.setVisibility(View.GONE); } else { // this is a public key - show if it's verified - h.mStatus.setImageDrawable( - getResources().getDrawable(R.drawable.status_signature_verified_cutout)); - h.mStatus.setColorFilter(getResources().getColor(R.color.android_green_dark), - PorterDuff.Mode.SRC_ATOP); + KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, KeyFormattingUtils.STATE_VERIFIED); h.mStatus.setVisibility(View.VISIBLE); } } else { 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 dd389a587..dad1f19a8 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 @@ -19,10 +19,14 @@ package org.sufficientlysecure.keychain.ui.util; import android.content.Context; +import android.database.Cursor; import android.graphics.Color; +import android.graphics.PorterDuff; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.widget.ImageView; import org.spongycastle.asn1.ASN1ObjectIdentifier; import org.spongycastle.asn1.nist.NISTNamedCurves; @@ -330,4 +334,41 @@ public class KeyFormattingUtils { ((int) digest[2] + 256) % 256}; } + 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; + + /** + * returns true if status has been set, if false no status! + */ + public static void setStatusImage(Context context, ImageView statusView, int state) { + switch (state) { + case STATE_REVOKED: + statusView.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout)); + statusView.setColorFilter(context.getResources().getColor(R.color.android_red_dark), + PorterDuff.Mode.SRC_ATOP); + break; + case STATE_EXPIRED: + statusView.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_expired_cutout)); + statusView.setColorFilter(context.getResources().getColor(R.color.android_orange_dark), + PorterDuff.Mode.SRC_ATOP); + break; + case STATE_UNAVAILABLE: + statusView.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); + statusView.setColorFilter(context.getResources().getColor(R.color.bg_gray), + PorterDuff.Mode.SRC_ATOP); + break; + case STATE_VERIFIED: + statusView.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_verified_cutout)); + statusView.setColorFilter(context.getResources().getColor(R.color.android_green_dark), + PorterDuff.Mode.SRC_ATOP); + break; + } + } + } 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 7224c4b03..07f6529f1 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 @@ -24,10 +24,13 @@ import android.os.Bundle; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.util.AttributeSet; +import android.widget.ImageView; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; public class CertifyKeySpinner extends KeySpinner { private long mHiddenMasterKeyId = Constants.key.none; @@ -61,22 +64,23 @@ public class CertifyKeySpinner extends KeySpinner { KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.KEY_ID, KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, KeychainContract.KeyRings.IS_EXPIRED, KeychainContract.KeyRings.HAS_CERTIFY, KeychainContract.KeyRings.HAS_ANY_SECRET }; String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " - + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND " - + Tables.KEYS + "." + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " - + KeychainContract.KeyRings.IS_EXPIRED + " = 0 AND " + KeychainDatabase.Tables.KEYS + "." - + KeychainContract.KeyRings.MASTER_KEY_ID + " != " + mHiddenMasterKeyId; + + KeychainDatabase.Tables.KEYS + "." + KeychainContract.KeyRings.MASTER_KEY_ID + + " != " + mHiddenMasterKeyId; // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. return new CursorLoader(getContext(), baseUri, projection, where, null, null); } + private int mIndexHasCertify, mIndexIsRevoked, mIndexIsExpired; + @Override public void onLoadFinished(Loader loader, Cursor data) { super.onLoadFinished(loader, data); @@ -84,6 +88,29 @@ public class CertifyKeySpinner extends KeySpinner { if (mAdapter.getCount() == 2) { setSelection(1); } + mIndexHasCertify = data.getColumnIndex(KeychainContract.KeyRings.HAS_CERTIFY); + mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED); + mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED); + } + + @Override + boolean setStatus(Context context, Cursor cursor, ImageView statusView) { + if (cursor.getInt(mIndexIsRevoked) != 0) { + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_REVOKED); + return false; + } + if (cursor.getInt(mIndexIsExpired) != 0) { + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_EXPIRED); + return false; + } + // don't invalidate the "None" entry, which is also null! + if (cursor.getPosition() != 0 && cursor.isNull(mIndexHasCertify)) { + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_UNAVAILABLE); + return false; + } + + // valid key + return true; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index 63287c799..df8250ab6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -29,6 +29,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; +import android.widget.ImageView; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TextView; @@ -139,21 +140,28 @@ public abstract class KeySpinner extends Spinner implements LoaderManager.Loader @Override public void bindView(View view, Context context, Cursor cursor) { + TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name); + ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status); + TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email); + TextView vKeyId = (TextView) view.findViewById(R.id.keyspinner_key_id); + String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId)); - TextView vKeyName = ((TextView) view.findViewById(R.id.keyspinner_key_name)); - TextView vKeyStatus = ((TextView) view.findViewById(R.id.keyspinner_key_status)); vKeyName.setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")")); - ((TextView) view.findViewById(R.id.keyspinner_key_email)).setText(userId[1]); - ((TextView) view.findViewById(R.id.keyspinner_key_id)).setText(KeyFormattingUtils.convertKeyIdToHex(cursor.getLong(mIndexKeyId))); - String status = getStatus(getContext(), cursor); - if (status == null) { + vKeyEmail.setText(userId[1]); + vKeyId.setText(KeyFormattingUtils.convertKeyIdToHex(cursor.getLong(mIndexKeyId))); + + boolean valid = setStatus(getContext(), cursor, vKeyStatus); + if (valid) { vKeyName.setTextColor(Color.BLACK); + vKeyEmail.setTextColor(Color.BLACK); + vKeyId.setTextColor(Color.BLACK); vKeyStatus.setVisibility(View.GONE); view.setClickable(false); } else { vKeyName.setTextColor(Color.GRAY); + vKeyEmail.setTextColor(Color.GRAY); + vKeyId.setTextColor(Color.GRAY); vKeyStatus.setVisibility(View.VISIBLE); - vKeyStatus.setText(status); // this is a HACK. the trick is, if the element itself is clickable, the // click is not passed on to the view list view.setClickable(true); @@ -228,19 +236,19 @@ public abstract class KeySpinner extends Spinner implements LoaderManager.Loader } ((TextView) v.findViewById(R.id.keyspinner_key_name)).setText(R.string.choice_none); v.findViewById(R.id.keyspinner_key_email).setVisibility(View.GONE); - v.findViewById(R.id.keyspinner_key_row).setVisibility(View.GONE); + v.findViewById(R.id.keyspinner_key_id).setVisibility(View.GONE); + v.findViewById(R.id.keyspinner_key_status).setVisibility(View.GONE); } else { v = inner.getView(position - 1, convertView, parent); v.findViewById(R.id.keyspinner_key_email).setVisibility(View.VISIBLE); - v.findViewById(R.id.keyspinner_key_row).setVisibility(View.VISIBLE); + v.findViewById(R.id.keyspinner_key_id).setVisibility(View.VISIBLE); } return v; } } - /** Return a string which should be the disabled status of the key, or null if the key is enabled. */ - String getStatus(Context context, Cursor cursor) { - return null; + boolean setStatus(Context context, Cursor cursor, ImageView statusView) { + return true; } } 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 648fcd4eb..ce1f7bb44 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 @@ -24,9 +24,11 @@ import android.os.Bundle; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.util.AttributeSet; +import android.widget.ImageView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; public class SignKeySpinner extends KeySpinner { public SignKeySpinner(Context context) { @@ -69,25 +71,30 @@ public class SignKeySpinner extends KeySpinner { private int mIndexHasSign, mIndexIsRevoked, mIndexIsExpired; @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - super.onLoadFinished(loader, cursor); - mIndexHasSign = cursor.getColumnIndex(KeychainContract.KeyRings.HAS_SIGN); - mIndexIsRevoked = cursor.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED); - mIndexIsExpired = cursor.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED); + public void onLoadFinished(Loader loader, Cursor data) { + super.onLoadFinished(loader, data); + mIndexHasSign = data.getColumnIndex(KeychainContract.KeyRings.HAS_SIGN); + mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED); + mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED); } @Override - String getStatus(Context context, Cursor cursor) { + boolean setStatus(Context context, Cursor cursor, ImageView statusView) { if (cursor.getInt(mIndexIsRevoked) != 0) { - return context.getString(R.string.revoked); - } - if (cursor.getInt(mIndexHasSign) == 0) { - return context.getString(R.string.key_unavailable); + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_REVOKED); + return false; } if (cursor.getInt(mIndexIsExpired) != 0) { - return context.getString(R.string.expired); + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_EXPIRED); + return false; } - return null; + if (cursor.getInt(mIndexHasSign) == 0) { + KeyFormattingUtils.setStatusImage(getContext(), statusView, KeyFormattingUtils.STATE_UNAVAILABLE); + return false; + } + + // valid key + return true; } } diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml index 8d600464c..a7a195ffa 100644 --- a/OpenKeychain/src/main/res/layout/key_list_item.xml +++ b/OpenKeychain/src/main/res/layout/key_list_item.xml @@ -39,9 +39,9 @@ diff --git a/OpenKeychain/src/main/res/layout/keyspinner_item.xml b/OpenKeychain/src/main/res/layout/keyspinner_item.xml index c519a92cc..e231664f3 100644 --- a/OpenKeychain/src/main/res/layout/keyspinner_item.xml +++ b/OpenKeychain/src/main/res/layout/keyspinner_item.xml @@ -1,63 +1,59 @@ + android:gravity="center_vertical" + android:singleLine="true" + android:orientation="horizontal" + android:descendantFocusability="blocksDescendants" + android:focusable="false"> - - - - - + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:focusable="true" + android:orientation="vertical" + android:paddingLeft="8dp" + android:paddingRight="4dp" + android:paddingTop="4dp" + android:paddingBottom="4dp"> + android:text="@string/label_main_user_id" + android:textAppearance="?android:attr/textAppearanceMedium" /> + android:text="user@example.com" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + + \ No newline at end of file