first steps in ui towards confirmation of linked ids

This commit is contained in:
Vincent Breitmoser 2015-03-06 14:20:58 +01:00
parent a2419aa688
commit 6e17d5244d
8 changed files with 426 additions and 253 deletions

View File

@ -261,7 +261,6 @@ public class ViewKeyActivity extends BaseActivity implements
initNfc(mDataUri); initNfc(mDataUri);
startFragment(savedInstanceState, mDataUri);
} }
@Override @Override
@ -269,26 +268,6 @@ public class ViewKeyActivity extends BaseActivity implements
setContentView(R.layout.view_key_activity); setContentView(R.layout.view_key_activity);
} }
private void startFragment(Bundle savedInstanceState, Uri dataUri) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of the fragment
ViewKeyFragment frag = ViewKeyFragment.newInstance(dataUri);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction()
.replace(R.id.view_key_fragment, frag, "main")
.commitAllowingStateLoss();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
@ -807,7 +786,24 @@ public class ViewKeyActivity extends BaseActivity implements
// old cursor once we return.) // old cursor once we return.)
switch (loader.getId()) { switch (loader.getId()) {
case LOADER_ID_UNIFIED: { case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) { // if there is no data, just break
if (!data.moveToFirst()) {
break;
}
String oldFingerprint = mFingerprint;
mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
byte[] fpData = data.getBlob(INDEX_FINGERPRINT);
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(fpData);
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0;
mIsRevoked = data.getInt(INDEX_IS_REVOKED) > 0;
mIsExpired = data.getInt(INDEX_IS_EXPIRED) != 0;
mIsVerified = data.getInt(INDEX_VERIFIED) > 0;
startFragment(mIsSecret, fpData);
// get name, email, and comment from USER_ID // get name, email, and comment from USER_ID
String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID)); String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID));
if (mainUserId[0] != null) { if (mainUserId[0] != null) {
@ -816,16 +812,6 @@ public class ViewKeyActivity extends BaseActivity implements
mName.setText(R.string.user_id_no_name); mName.setText(R.string.user_id_no_name);
} }
String oldFingerprint = mFingerprint;
mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT));
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0;
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 // if the refresh animation isn't playing
if (!mRotate.hasStarted() && !mRotateSpin.hasStarted()) { if (!mRotate.hasStarted() && !mRotateSpin.hasStarted()) {
// re-create options menu based on mIsSecret, mIsVerified // re-create options menu based on mIsSecret, mIsVerified
@ -969,10 +955,23 @@ public class ViewKeyActivity extends BaseActivity implements
} }
} }
} }
}
@Override @Override
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<Cursor> loader) {
} }
private void startFragment(boolean isSecret, byte[] fingerprint) {
// Create an instance of the fragment
ViewKeyFragment frag = ViewKeyFragment.newInstance(mDataUri, isSecret, fingerprint);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction()
.replace(R.id.view_key_fragment, frag, "main")
.commitAllowingStateLoss();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
}
} }

View File

@ -29,7 +29,6 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.transition.Explode;
import android.transition.Fade; import android.transition.Fade;
import android.transition.Transition; import android.transition.Transition;
import android.transition.TransitionInflater; import android.transition.TransitionInflater;
@ -47,21 +46,21 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
public class ViewKeyFragment extends LoaderFragment implements public class ViewKeyFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri"; public static final String ARG_DATA_URI = "uri";
private static final String ARG_FINGERPRINT = "fingerprint";
private static final String ARG_IS_SECRET = "is_secret";
private ListView mUserIds; private ListView mUserIds;
boolean mIsSecret = false; boolean mIsSecret = false;
private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 0;
private static final int LOADER_ID_USER_IDS = 1; private static final int LOADER_ID_LINKED_IDS = 1;
private static final int LOADER_ID_LINKED_IDS = 2;
private UserIdsAdapter mUserIdsAdapter; private UserIdsAdapter mUserIdsAdapter;
private LinkedIdsAdapter mLinkedIdsAdapter; private LinkedIdsAdapter mLinkedIdsAdapter;
@ -69,20 +68,40 @@ public class ViewKeyFragment extends LoaderFragment implements
private Uri mDataUri; private Uri mDataUri;
private ListView mLinkedIds; private ListView mLinkedIds;
private CardView mLinkedIdsCard; private CardView mLinkedIdsCard;
private byte[] mFingerprint;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */
public static ViewKeyFragment newInstance(Uri dataUri) { public static ViewKeyFragment newInstance(Uri dataUri, boolean isSecret, byte[] fingerprint) {
ViewKeyFragment frag = new ViewKeyFragment(); ViewKeyFragment frag = new ViewKeyFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putParcelable(ARG_DATA_URI, dataUri); args.putParcelable(ARG_DATA_URI, dataUri);
args.putBoolean(ARG_IS_SECRET, isSecret);
args.putByteArray(ARG_FINGERPRINT, fingerprint);
frag.setArguments(args); frag.setArguments(args);
return frag; return frag;
} }
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = getArguments();
Uri dataUri = args.getParcelable(ARG_DATA_URI);
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
getActivity().finish();
return;
}
boolean isSecret = args.getBoolean(ARG_IS_SECRET);
byte[] fingerprint = args.getByteArray(ARG_FINGERPRINT);
loadData(dataUri, isSecret, fingerprint);
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
View root = super.onCreateView(inflater, superContainer, savedInstanceState); View root = super.onCreateView(inflater, superContainer, savedInstanceState);
@ -112,7 +131,7 @@ public class ViewKeyFragment extends LoaderFragment implements
private void showLinkedId(final int position) { private void showLinkedId(final int position) {
Fragment frag; Fragment frag;
try { try {
frag = mLinkedIdsAdapter.getLinkedIdFragment(position); frag = mLinkedIdsAdapter.getLinkedIdFragment(position, mFingerprint);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return; return;
@ -149,45 +168,28 @@ public class ViewKeyFragment extends LoaderFragment implements
} }
} }
@Override private void loadData(Uri dataUri, boolean isSecret, byte[] fingerprint) {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
getActivity().finish();
return;
}
loadData(dataUri);
}
// These are the rows that we will retrieve.
static final String[] UNIFIED_PROJECTION = new String[]{
KeychainContract.KeyRings._ID,
KeychainContract.KeyRings.HAS_ANY_SECRET,
};
static final int INDEX_HAS_ANY_SECRET = 1;
private void loadData(Uri dataUri) {
mDataUri = dataUri; mDataUri = dataUri;
mIsSecret = isSecret;
mFingerprint = fingerprint;
Log.i(Constants.TAG, "mDataUri: " + mDataUri); Log.i(Constants.TAG, "mDataUri: " + mDataUri);
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); // load user ids after we know if it's a secret key
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null);
mUserIds.setAdapter(mUserIdsAdapter);
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
mLinkedIdsAdapter = new LinkedIdsAdapter(getActivity(), null, 0, !mIsSecret);
mLinkedIds.setAdapter(mLinkedIdsAdapter);
getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this);
} }
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
setContentShown(false); setContentShown(false);
switch (id) { switch (id) {
case LOADER_ID_UNIFIED: {
Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri);
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
}
case LOADER_ID_USER_IDS: case LOADER_ID_USER_IDS:
return UserIdsAdapter.createLoader(getActivity(), mDataUri); return UserIdsAdapter.createLoader(getActivity(), mDataUri);
@ -203,28 +205,6 @@ public class ViewKeyFragment extends LoaderFragment implements
// Swap the new cursor in. (The framework will take care of closing the // Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.) // old cursor once we return.)
switch (loader.getId()) { switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
// Avoid NullPointerExceptions...
if (data.getCount() == 0) {
return;
}
if (data.moveToFirst()) {
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
// load user ids after we know if it's a secret key
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null);
mUserIds.setAdapter(mUserIdsAdapter);
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
mLinkedIdsAdapter = new LinkedIdsAdapter(getActivity(), null, 0, !mIsSecret);
mLinkedIds.setAdapter(mLinkedIdsAdapter);
getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this);
break;
}
}
case LOADER_ID_USER_IDS: { case LOADER_ID_USER_IDS: {
mUserIdsAdapter.swapCursor(data); mUserIdsAdapter.swapCursor(data);
break; break;

View File

@ -125,7 +125,7 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null); UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null);
} }
public Fragment getLinkedIdFragment(int position) throws IOException { public Fragment getLinkedIdFragment(int position, byte[] fingerprint) throws IOException {
RawLinkedIdentity id = getItem(position); RawLinkedIdentity id = getItem(position);
Integer isVerified; Integer isVerified;
@ -137,7 +137,7 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
isVerified = null; isVerified = null;
} }
return LinkedIdViewFragment.newInstance(id, isVerified); return LinkedIdViewFragment.newInstance(id, isVerified, fingerprint);
} }
public static class ViewHolder { public static class ViewHolder {

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
@ -11,8 +12,13 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource;
import org.sufficientlysecure.keychain.pgp.linked.LinkedIdentity; import org.sufficientlysecure.keychain.pgp.linked.LinkedIdentity;
import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; import org.sufficientlysecure.keychain.pgp.linked.LinkedResource;
@ -21,12 +27,15 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter.ViewHolder; import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter.ViewHolder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
public class LinkedIdViewFragment extends Fragment { public class LinkedIdViewFragment extends Fragment {
private static final String EXTRA_ENCODED_LID = "encoded_lid"; private static final String ARG_ENCODED_LID = "encoded_lid";
private static final String EXTRA_VERIFIED = "verified"; private static final String ARG_VERIFIED = "verified";
private static final String ARG_FINGERPRINT = "fingerprint";
private RawLinkedIdentity mLinkedId; private RawLinkedIdentity mLinkedId;
private LinkedCookieResource mLinkedResource; private LinkedCookieResource mLinkedResource;
@ -34,13 +43,20 @@ public class LinkedIdViewFragment extends Fragment {
private CardView vLinkedIdsCard; private CardView vLinkedIdsCard;
private Context mContext; private Context mContext;
private byte[] mFingerprint;
private LayoutInflater mInflater;
private LinearLayout vLinkedCerts;
private View mCurrentCert;
private boolean mInProgress;
private ViewAnimator mButtonSwitcher;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle args = getArguments(); Bundle args = getArguments();
byte[] data = args.getByteArray(EXTRA_ENCODED_LID); byte[] data = args.getByteArray(ARG_ENCODED_LID);
try { try {
mLinkedId = LinkedIdentity.fromAttributeData(data); mLinkedId = LinkedIdentity.fromAttributeData(data);
@ -55,19 +71,24 @@ public class LinkedIdViewFragment extends Fragment {
mLinkedResource = (LinkedCookieResource) res; mLinkedResource = (LinkedCookieResource) res;
} }
mVerified = args.containsKey(EXTRA_VERIFIED) ? args.getInt(EXTRA_VERIFIED) : null; mVerified = args.containsKey(ARG_VERIFIED) ? args.getInt(ARG_VERIFIED) : null;
mFingerprint = args.getByteArray(ARG_FINGERPRINT);
mContext = getActivity(); mContext = getActivity();
mInflater = getLayoutInflater(savedInstanceState);
} }
public static Fragment newInstance(RawLinkedIdentity id, Integer isVerified) throws IOException { public static Fragment newInstance(RawLinkedIdentity id,
Integer isVerified, byte[] fingerprint) throws IOException {
LinkedIdViewFragment frag = new LinkedIdViewFragment(); LinkedIdViewFragment frag = new LinkedIdViewFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putByteArray(EXTRA_ENCODED_LID, id.toUserAttribute().getEncoded()); args.putByteArray(ARG_ENCODED_LID, id.toUserAttribute().getEncoded());
if (isVerified != null) { if (isVerified != null) {
args.putInt(EXTRA_VERIFIED, isVerified); args.putInt(ARG_VERIFIED, isVerified);
} }
args.putByteArray(ARG_FINGERPRINT, fingerprint);
frag.setArguments(args); frag.setArguments(args);
return frag; return frag;
@ -78,6 +99,7 @@ public class LinkedIdViewFragment extends Fragment {
View root = inflater.inflate(R.layout.linked_id_view_fragment, null); View root = inflater.inflate(R.layout.linked_id_view_fragment, null);
vLinkedIdsCard = (CardView) root.findViewById(R.id.card_linked_ids); vLinkedIdsCard = (CardView) root.findViewById(R.id.card_linked_ids);
vLinkedCerts = (LinearLayout) root.findViewById(R.id.linked_id_certs);
View back = root.findViewById(R.id.back_button); View back = root.findViewById(R.id.back_button);
back.setClickable(true); back.setClickable(true);
@ -136,6 +158,8 @@ public class LinkedIdViewFragment extends Fragment {
button_view.setVisibility(View.GONE); button_view.setVisibility(View.GONE);
} }
mButtonSwitcher = (ViewAnimator) root.findViewById(R.id.button_animator);
View button_verify = root.findViewById(R.id.button_verify); View button_verify = root.findViewById(R.id.button_verify);
button_verify.setOnClickListener(new OnClickListener() { button_verify.setOnClickListener(new OnClickListener() {
@Override @Override
@ -144,12 +168,88 @@ public class LinkedIdViewFragment extends Fragment {
} }
}); });
View button_retry = root.findViewById(R.id.button_retry);
button_retry.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
verifyResource();
}
});
View button_confirm = root.findViewById(R.id.button_confirm);
button_confirm.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Notify.createNotify(getActivity(), "confirmed!", Notify.LENGTH_LONG, Style.INFO).show();
}
});
return root; 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);
}
}
public void verifyResource() { public void verifyResource() {
// TODO // only one at a time
synchronized (this) {
if (mInProgress) {
return;
}
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);
vLinkedCerts.addView(mCurrentCert);
} else {
holder = (ViewHolderCert) mCurrentCert.getTag();
}
holder.setShowProgress(true);
holder.vText.setText("Verifying…");
new AsyncTask<Void,Void,LinkedVerifyResult>() {
@Override
protected LinkedVerifyResult doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// nvm
}
return mLinkedResource.verify(mFingerprint, mLinkedId.mNonce);
}
@Override
protected void onPostExecute(LinkedVerifyResult result) {
holder.setShowProgress(false);
if (result.success()) {
mButtonSwitcher.setDisplayedChild(2);
holder.vText.setText("Ok");
} else {
mButtonSwitcher.setDisplayedChild(1);
holder.vText.setText("Error");
}
mInProgress = false;
}
}.execute();
} }

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:interpolator="@android:anim/bounce_interpolator"
android:duration="700"
/>
</set>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="300"
/>
</set>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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>

View File

@ -31,6 +31,14 @@
<include layout="@layout/linked_id_item" /> <include layout="@layout/linked_id_item" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:id="@+id/linked_id_certs">
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -57,14 +65,34 @@
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
/> />
<ViewAnimator
android:id="@+id/button_animator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inAnimation="@anim/fade_in"
android:outAnimation="@anim/fade_out">
<Button <Button
android:id="@+id/verify_button" android:id="@+id/button_verify"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Verify" android:text="Verify"
android:textColor="@color/link_text_material_light" android:textColor="@color/link_text_material_light"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle" />
/> <Button
android:id="@+id/button_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Retry"
android:textColor="@color/link_text_material_light"
style="?android:attr/borderlessButtonStyle" />
<Button
android:id="@+id/button_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Confirm"
android:textColor="@color/link_text_material_light"
style="?android:attr/borderlessButtonStyle" />
</ViewAnimator>
</LinearLayout> </LinearLayout>