diff options
6 files changed, 295 insertions, 80 deletions
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 97c8a6d5e..8a39cafc6 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -20,6 +20,7 @@ dependencies { compile 'it.neokree:MaterialNavigationDrawer:1.3.1' compile 'com.nispok:snackbar:2.9.1' compile 'com.getbase:floatingactionbutton:1.8.0' + compile 'com.ocpsoft:ocpsoft-pretty-time:1.0.6' // libs as submodules compile project(':extern:openpgp-api-lib') 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 59e0efbd0..3edadec2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -839,9 +839,7 @@ public class ViewKeyActivity extends BaseActivity implements mIsExpired = data.getInt(INDEX_IS_EXPIRED) != 0; mIsVerified = data.getInt(INDEX_VERIFIED) > 0; - if (oldFingerprint == null) { - startFragment(mIsSecret, fpData); - } + startFragment(mIsSecret, fpData); // get name, email, and comment from USER_ID String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID)); @@ -1000,21 +998,25 @@ public class ViewKeyActivity extends BaseActivity implements } - private void startFragment(boolean isSecret, byte[] fingerprint) { - // Create an instance of the fragment - final ViewKeyFragment frag = ViewKeyFragment.newInstance(mDataUri, isSecret, fingerprint); - + private void startFragment(final boolean isSecret, final byte[] fingerprint) { new Handler().post(new Runnable() { @Override public void run() { FragmentManager manager = getSupportFragmentManager(); - manager.popBackStack("linked_id", FragmentManager.POP_BACK_STACK_INCLUSIVE); - // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - manager.beginTransaction() - .replace(R.id.view_key_fragment, frag, "main") - .commit(); + if (manager.getBackStackEntryCount() == 0) { + // Create an instance of the fragment + final ViewKeyFragment frag = ViewKeyFragment.newInstance( + mDataUri, isSecret, fingerprint); + manager.beginTransaction() + .replace(R.id.view_key_fragment, frag) + .commit(); + manager.popBackStack(); + } else { + // not sure yet if we actually want this! + // manager.popBackStack(); + } + } }); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java index 284e6e0c1..5b8d14c4c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java @@ -22,7 +22,6 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.ViewAnimator; @@ -44,10 +43,10 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsCertAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; +import org.sufficientlysecure.keychain.ui.widget.CertListWidget; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import org.sufficientlysecure.keychain.util.Log; @@ -61,8 +60,7 @@ public class LinkedIdViewFragment extends Fragment implements private static final String ARG_LID_RANK = "rank"; private static final String ARG_SHOWCERT = "verified"; private static final String ARG_FINGERPRINT = "fingerprint"; - private static final int LOADER_ID_LINKED_CERTS = 1; - private static final int LOADER_ID_LINKED_ID = 2; + private static final int LOADER_ID_LINKED_ID = 1; private RawLinkedIdentity mLinkedId; private LinkedCookieResource mLinkedResource; @@ -74,10 +72,8 @@ public class LinkedIdViewFragment extends Fragment implements private boolean mInProgress; - private LinkedIdsCertAdapter mCertAdapter; private Uri mDataUri; private ViewHolder mViewHolder; - private View mCurrentCert; private int mLidRank; private OnIdentityLoadedListener mIdLoadedListener; @@ -109,11 +105,9 @@ public class LinkedIdViewFragment extends Fragment implements mContext = getActivity(); mInflater = getLayoutInflater(savedInstanceState); - mCertAdapter = new LinkedIdsCertAdapter(getActivity(), null, 0); - // getLoaderManager().initLoader(LOADER_ID_LINKED_CERTS, null, this); getLoaderManager().initLoader(LOADER_ID_LINKED_ID, null, this); - } + @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { switch (id) { @@ -122,10 +116,6 @@ public class LinkedIdViewFragment extends Fragment implements UserIdsAdapter.USER_PACKETS_PROJECTION, Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Integer.toString(mLidRank), null, null); - - case LOADER_ID_LINKED_CERTS: - return LinkedIdsCertAdapter.createLoader(getActivity(), mDataUri); - default: return null; } @@ -162,10 +152,6 @@ public class LinkedIdViewFragment extends Fragment implements } break; - - case LOADER_ID_LINKED_CERTS: - mCertAdapter.swapCursor(cursor); - break; } } @@ -180,6 +166,16 @@ public class LinkedIdViewFragment extends Fragment implements private void loadIdentity(RawLinkedIdentity linkedId, int certStatus) { mLinkedId = linkedId; + mViewHolder.setShowVerifying(false); + + { + Bundle args = new Bundle(); + args.putParcelable(CertListWidget.ARG_URI, mDataUri); + args.putInt(CertListWidget.ARG_RANK, mLidRank); + getLoaderManager().initLoader(CertListWidget.LOADER_ID_LINKED_CERTS, + args, mViewHolder.vLinkedCerts); + } + if (mLinkedId instanceof LinkedIdentity) { LinkedResource res = ((LinkedIdentity) mLinkedId).mResource; mLinkedResource = (LinkedCookieResource) res; @@ -235,30 +231,28 @@ public class LinkedIdViewFragment extends Fragment implements @Override public void onLoaderReset(Loader<Cursor> loader) { - switch (loader.getId()) { - case LOADER_ID_LINKED_CERTS: - mCertAdapter.swapCursor(null); - break; - } } static class ViewHolder { private final View vButtonView; + private final ViewAnimator vVerifyingContainer; LinkedIdsAdapter.ViewHolder mLinkedIdHolder; private ViewAnimator mButtonSwitcher; - private LinearLayout vLinkedCerts; + private CertListWidget vLinkedCerts; private CertifyKeySpinner vKeySpinner; - private LinearLayout vLinkedVerify; private final View vButtonVerify; private final View vButtonRetry; private final View vButtonConfirm; private final View vButtonBack; + private final ViewAnimator vProgress; + private final ImageView vIcon; + private final TextView vText; + ViewHolder(View root) { - vLinkedCerts = (LinearLayout) root.findViewById(R.id.linked_id_certs); - vLinkedVerify = (LinearLayout) root.findViewById(R.id.linked_id_verify); + vLinkedCerts = (CertListWidget) root.findViewById(R.id.linked_id_certs); vKeySpinner = (CertifyKeySpinner) root.findViewById(R.id.cert_key_spinner); mButtonSwitcher = (ViewAnimator) root.findViewById(R.id.button_animator); @@ -269,6 +263,26 @@ public class LinkedIdViewFragment extends Fragment implements vButtonRetry = root.findViewById(R.id.button_retry); vButtonConfirm = root.findViewById(R.id.button_confirm); vButtonView = root.findViewById(R.id.button_view); + + vVerifyingContainer = (ViewAnimator) root.findViewById(R.id.linked_verify_container); + + vProgress = (ViewAnimator) root.findViewById(R.id.linked_cert_progress); + vIcon = (ImageView) root.findViewById(R.id.linked_cert_icon); + vText = (TextView) root.findViewById(R.id.linked_cert_text); + } + + void setShowVerifying(boolean show) { + int child = show ? 1 : 0; + if (vVerifyingContainer.getDisplayedChild() != child) { + vVerifyingContainer.setDisplayedChild(child); + } + if (!show) { + vKeySpinner.setVisibility(View.GONE); + } + } + + void setShowProgress(boolean show) { + vProgress.setDisplayedChild(show ? 0 : 1); } } @@ -310,21 +324,6 @@ public class LinkedIdViewFragment extends Fragment implements return root; } - static class ViewHolderCert { - final ViewAnimator vProgress; - final ImageView vIcon; - final TextView vText; - - ViewHolderCert(View view) { - vProgress = (ViewAnimator) view.findViewById(R.id.linked_cert_progress); - vIcon = (ImageView) view.findViewById(R.id.linked_cert_icon); - vText = (TextView) view.findViewById(R.id.linked_cert_text); - } - void setShowProgress(boolean show) { - vProgress.setDisplayedChild(show ? 0 : 1); - } - } - void showButton(int which) { if (mViewHolder.mButtonSwitcher.getDisplayedChild() == which) { return; @@ -342,20 +341,11 @@ public class LinkedIdViewFragment extends Fragment implements mInProgress = true; } - // is there a current certification? if not create a new one - final ViewHolderCert holder; - if (mCurrentCert == null) { - mCurrentCert = mInflater.inflate(R.layout.linked_id_cert, null); - holder = new ViewHolderCert(mCurrentCert); - mCurrentCert.setTag(holder); - mViewHolder.vLinkedVerify.addView(mCurrentCert); - } else { - holder = (ViewHolderCert) mCurrentCert.getTag(); - } + mViewHolder.setShowVerifying(true); mViewHolder.vKeySpinner.setVisibility(View.GONE); - holder.setShowProgress(true); - holder.vText.setText("Verifying…"); + mViewHolder.setShowProgress(true); + mViewHolder.vText.setText("Verifying…"); new AsyncTask<Void,Void,LinkedVerifyResult>() { @Override @@ -376,13 +366,13 @@ public class LinkedIdViewFragment extends Fragment implements @Override protected void onPostExecute(LinkedVerifyResult result) { - holder.setShowProgress(false); + mViewHolder.setShowProgress(false); if (result.success()) { - holder.vText.setText("Ok"); + mViewHolder.vText.setText("Ok"); setupForConfirmation(); } else { showButton(1); - holder.vText.setText("Error"); + mViewHolder.vText.setText("Error"); } mInProgress = false; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java new file mode 100644 index 000000000..3e9cffb69 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java @@ -0,0 +1,131 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.text.SpannableStringBuilder; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; +import android.widget.ViewAnimator; + +import com.ocpsoft.pretty.time.PrettyTime; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; + +public class CertListWidget extends ViewAnimator + implements LoaderManager.LoaderCallbacks<Cursor> { + + public static final int LOADER_ID_LINKED_CERTS = 38572; + + public static final String ARG_URI = "uri"; + public static final String ARG_RANK = "rank"; + + + // These are the rows that we will retrieve. + static final String[] CERTS_PROJECTION = new String[]{ + KeychainContract.Certs._ID, + KeychainContract.Certs.MASTER_KEY_ID, + KeychainContract.Certs.VERIFIED, + KeychainContract.Certs.TYPE, + KeychainContract.Certs.RANK, + KeychainContract.Certs.KEY_ID_CERTIFIER, + KeychainContract.Certs.USER_ID, + KeychainContract.Certs.SIGNER_UID, + KeychainContract.Certs.CREATION + }; + public static final int INDEX_MASTER_KEY_ID = 1; + public static final int INDEX_VERIFIED = 2; + public static final int INDEX_TYPE = 3; + public static final int INDEX_RANK = 4; + public static final int INDEX_KEY_ID_CERTIFIER = 5; + public static final int INDEX_USER_ID = 6; + public static final int INDEX_SIGNER_UID = 7; + public static final int INDEX_CREATION = 8; + + private TextView vCollapsed; + private View vExpanded; + private View vExpandButton; + + public CertListWidget(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + View root = getRootView(); + vCollapsed = (TextView) root.findViewById(R.id.cert_collapsed_list); + vExpanded = root.findViewById(R.id.cert_expanded_list); + vExpandButton = root.findViewById(R.id.cert_expand_button); + + // for now + vExpandButton.setVisibility(View.GONE); + } + + void setExpanded(boolean expanded) { + setDisplayedChild(expanded ? 1 : 0); + } + + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + Uri baseUri = args.getParcelable(ARG_URI); + int rank = args.getInt(ARG_RANK); + + Uri uri = Certs.buildLinkedIdCertsUri(baseUri, rank); + return new CursorLoader(getContext(), uri, + CERTS_PROJECTION, null, null, null); + + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + + if (data == null || !data.moveToFirst()) { + return; + } + + setVisibility(View.VISIBLE); + + // TODO support external certificates + Date userCert = null; + while (!data.isAfterLast()) { + + int verified = data.getInt(INDEX_VERIFIED); + Date creation = new Date(data.getLong(INDEX_CREATION) * 1000); + + if (verified == Certs.VERIFIED_SECRET) { + if (userCert == null || userCert.after(creation)) { + userCert = creation; + } + } + + data.moveToNext(); + } + + if (userCert != null) { + PrettyTime format = new PrettyTime(); + vCollapsed.setText("You verified and confirmed this identity " + + format.format(userCert) + "."); + } else { + vCollapsed.setText("This identity is not yet verified or confirmed."); + } + + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + setVisibility(View.GONE); + } + +} diff --git a/OpenKeychain/src/main/res/layout/cert_list_widget.xml b/OpenKeychain/src/main/res/layout/cert_list_widget.xml new file mode 100644 index 000000000..715e4bfa5 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/cert_list_widget.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.sufficientlysecure.keychain.ui.widget.CertListWidget + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginLeft="12dp" + android:layout_marginRight="12dp" + android:id="@+id/linked_id_certs"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:minHeight="?android:attr/listPreferredItemHeight" + > + + <TextView + android:id="@+id/cert_collapsed_list" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center_vertical" + android:layout_weight="1" + /> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_expand_more_black_24dp" + android:id="@+id/cert_expand_button" + android:padding="4dp" + /> + + </LinearLayout> + + <ListView + android:id="@+id/cert_expanded_list" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + </ListView> + +</org.sufficientlysecure.keychain.ui.widget.CertListWidget>
\ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml b/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml index b453167ea..4244de962 100644 --- a/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml +++ b/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml @@ -32,21 +32,68 @@ <include layout="@layout/linked_id_item" /> - <LinearLayout + <ViewAnimator android:layout_width="fill_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:animateLayoutChanges="true" - android:id="@+id/linked_id_certs"> + android:id="@+id/linked_verify_container" + android:inAnimation="@anim/fade_in" + android:outAnimation="@anim/fade_out"> + + <include layout="@layout/cert_list_widget" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" + android:singleLine="true"> + + <LinearLayout + android:orientation="vertical" + android:layout_gravity="center_vertical" + android:layout_width="0dip" + android:layout_marginLeft="16dp" + android:layout_marginTop="4dp" + android:layout_marginBottom="4dp" + android:layout_height="wrap_content" + android:layout_weight="1"> + + <TextView + android:id="@+id/linked_cert_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Verifying…" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + </LinearLayout> + + <ViewAnimator + android:layout_width="22dp" + android:layout_height="22dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" + android:layout_gravity="center" + android:id="@+id/linked_cert_progress" + android:inAnimation="@anim/fade_in" + android:outAnimation="@anim/fade_out"> + + <ProgressBar + android:layout_width="22dp" + android:layout_height="22dp" + android:indeterminate="true" + /> + + <ImageView + android:layout_width="22dp" + android:layout_height="wrap_content" + android:src="@drawable/status_signature_unknown_cutout_24dp" + android:id="@+id/linked_cert_icon" + /> + </ViewAnimator> + </LinearLayout> - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:animateLayoutChanges="true" - android:id="@+id/linked_id_verify"> - </LinearLayout> + </ViewAnimator> <org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner android:layout_marginLeft="14dp" |