New NFC dialog design with indeterminate progress, do NFC stuff in background

This commit is contained in:
Dominik Schürmann
2015-07-03 04:58:30 +02:00
parent d6b4d4b4f2
commit d03595f64e
11 changed files with 257 additions and 99 deletions

View File

@@ -692,6 +692,7 @@
--> -->
<activity <activity
android:name=".ui.NfcOperationActivity" android:name=".ui.NfcOperationActivity"
android:theme="@style/KeychainTheme.DialogWithoutTitle"
android:allowTaskReparenting="true" android:allowTaskReparenting="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:taskAffinity=":Nfc" /> android:taskAffinity=":Nfc" />

View File

@@ -63,6 +63,11 @@ public class CreateKeyActivity extends BaseNfcActivity {
Fragment mCurrentFragment; Fragment mCurrentFragment;
byte[] mScannedFingerprints;
byte[] mNfcAid;
String mNfcUserId;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -72,8 +77,6 @@ public class CreateKeyActivity extends BaseNfcActivity {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
try { try {
handleTagDiscoveredIntent(getIntent()); handleTagDiscoveredIntent(getIntent());
} catch (CardException e) {
handleNfcError(e);
} catch (IOException e) { } catch (IOException e) {
handleNfcError(e); handleNfcError(e);
} }
@@ -142,40 +145,47 @@ public class CreateKeyActivity extends BaseNfcActivity {
} }
@Override @Override
protected void onNfcPerform() throws IOException { protected void doNfcInBackground() throws IOException {
if (mCurrentFragment instanceof NfcListenerFragment) { if (mCurrentFragment instanceof NfcListenerFragment) {
((NfcListenerFragment) mCurrentFragment).onNfcPerform(); ((NfcListenerFragment) mCurrentFragment).doNfcInBackground();
return; return;
} }
byte[] scannedFingerprints = nfcGetFingerprints(); mScannedFingerprints = nfcGetFingerprints();
byte[] nfcAid = nfcGetAid(); mNfcAid = nfcGetAid();
String userId = nfcGetUserId(); mNfcUserId = nfcGetUserId();
}
if (containsKeys(scannedFingerprints)) { @Override
protected void onNfcPostExecute() throws IOException {
if (mCurrentFragment instanceof NfcListenerFragment) {
((NfcListenerFragment) mCurrentFragment).onNfcPostExecute();
return;
}
if (containsKeys(mScannedFingerprints)) {
try { try {
long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints); long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mScannedFingerprints);
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId); CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
ring.getMasterKeyId(); ring.getMasterKeyId();
Intent intent = new Intent(this, ViewKeyActivity.class); Intent intent = new Intent(this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, userId); intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, scannedFingerprints); intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mScannedFingerprints);
startActivity(intent); startActivity(intent);
finish(); finish();
} catch (PgpKeyNotFoundException e) { } catch (PgpKeyNotFoundException e) {
Fragment frag = CreateYubiKeyImportFragment.newInstance( Fragment frag = CreateYubiKeyImportFragment.newInstance(
scannedFingerprints, nfcAid, userId); mScannedFingerprints, mNfcAid, mNfcUserId);
loadFragment(frag, FragAction.TO_RIGHT); loadFragment(frag, FragAction.TO_RIGHT);
} }
} else { } else {
Fragment frag = CreateYubiKeyBlankFragment.newInstance(); Fragment frag = CreateYubiKeyBlankFragment.newInstance();
loadFragment(frag, FragAction.TO_RIGHT); loadFragment(frag, FragAction.TO_RIGHT);
} }
} }
private boolean containsKeys(byte[] scannedFingerprints) { private boolean containsKeys(byte[] scannedFingerprints) {
@@ -246,7 +256,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
} }
interface NfcListenerFragment { interface NfcListenerFragment {
public void onNfcPerform() throws IOException; public void doNfcInBackground() throws IOException;
public void onNfcPostExecute() throws IOException;
} }
} }

View File

@@ -195,7 +195,7 @@ public class CreateYubiKeyImportFragment
} }
@Override @Override
public void onNfcPerform() throws IOException { public void doNfcInBackground() throws IOException {
mNfcFingerprints = mCreateKeyActivity.nfcGetFingerprints(); mNfcFingerprints = mCreateKeyActivity.nfcGetFingerprints();
mNfcAid = mCreateKeyActivity.nfcGetAid(); mNfcAid = mCreateKeyActivity.nfcGetAid();
@@ -204,10 +204,13 @@ public class CreateYubiKeyImportFragment
byte[] fp = new byte[20]; byte[] fp = new byte[20];
ByteBuffer.wrap(fp).put(mNfcFingerprints, 0, 20); ByteBuffer.wrap(fp).put(mNfcFingerprints, 0, 20);
mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(fp); mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(fp);
}
@Override
public void onNfcPostExecute() throws IOException {
setData(); setData();
refreshSearch(); refreshSearch();
} }
@Override @Override

View File

@@ -448,10 +448,8 @@ public class ImportKeysActivity extends BaseNfcActivity
} }
@Override @Override
protected void onNfcPerform() throws IOException { protected void onNfcPostExecute() throws IOException {
// this displays the key or moves to the yubikey import dialogue. // either way, finish after NFC AsyncTask
super.onNfcPerform();
// either way, finish afterwards
finish(); finish();
} }
@@ -463,7 +461,7 @@ public class ImportKeysActivity extends BaseNfcActivity
} }
} }
public void handleResult (ImportKeyResult result) { public void handleResult(ImportKeyResult result) {
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction()) if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) { || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
Intent intent = new Intent(); Intent intent = new Intent();

View File

@@ -7,8 +7,10 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@@ -44,11 +46,15 @@ public class NfcOperationActivity extends BaseNfcActivity {
public static final String RESULT_DATA = "result_data"; public static final String RESULT_DATA = "result_data";
public ViewAnimator vAnimator;
private RequiredInputParcel mRequiredInput; private RequiredInputParcel mRequiredInput;
private Intent mServiceIntent; private Intent mServiceIntent;
private static final byte[] BLANK_FINGERPRINT = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private static final byte[] BLANK_FINGERPRINT = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
private CryptoInputParcel mInputParcel;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -56,6 +62,11 @@ public class NfcOperationActivity extends BaseNfcActivity {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setTitle(R.string.nfc_text);
vAnimator = (ViewAnimator) findViewById(R.id.view_animator);
vAnimator.setDisplayedChild(0);
Intent intent = getIntent(); Intent intent = getIntent();
Bundle data = intent.getExtras(); Bundle data = intent.getExtras();
@@ -74,16 +85,22 @@ public class NfcOperationActivity extends BaseNfcActivity {
} }
@Override @Override
protected void onNfcPerform() throws IOException { public void onNfcPreExecute() {
// start with indeterminate progress
vAnimator.setDisplayedChild(1);
}
CryptoInputParcel inputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); @Override
protected void doNfcInBackground() throws IOException {
mInputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime);
switch (mRequiredInput.mType) { switch (mRequiredInput.mType) {
case NFC_DECRYPT: { case NFC_DECRYPT: {
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
byte[] encryptedSessionKey = mRequiredInput.mInputData[i]; byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
byte[] decryptedSessionKey = nfcDecryptSessionKey(encryptedSessionKey); byte[] decryptedSessionKey = nfcDecryptSessionKey(encryptedSessionKey);
inputParcel.addCryptoData(encryptedSessionKey, decryptedSessionKey); mInputParcel.addCryptoData(encryptedSessionKey, decryptedSessionKey);
} }
break; break;
} }
@@ -92,7 +109,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
byte[] hash = mRequiredInput.mInputData[i]; byte[] hash = mRequiredInput.mInputData[i];
int algo = mRequiredInput.mSignAlgos[i]; int algo = mRequiredInput.mSignAlgos[i];
byte[] signedHash = nfcCalculateSignature(hash, algo); byte[] signedHash = nfcCalculateSignature(hash, algo);
inputParcel.addCryptoData(hash, signedHash); mInputParcel.addCryptoData(hash, signedHash);
} }
break; break;
} }
@@ -163,7 +180,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
} }
// TODO: Is this really needed? // TODO: Is this really needed?
inputParcel.addCryptoData(subkeyBytes, cardSerialNumber); mInputParcel.addCryptoData(subkeyBytes, cardSerialNumber);
} }
// change PINs afterwards // change PINs afterwards
@@ -177,16 +194,39 @@ public class NfcOperationActivity extends BaseNfcActivity {
} }
} }
}
@Override
protected void onNfcPostExecute() throws IOException {
if (mServiceIntent != null) { if (mServiceIntent != null) {
CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, inputParcel); CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, mInputParcel);
setResult(RESULT_OK, mServiceIntent); setResult(RESULT_OK, mServiceIntent);
} else { } else {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(NfcOperationActivity.RESULT_DATA, inputParcel); result.putExtra(NfcOperationActivity.RESULT_DATA, mInputParcel);
setResult(RESULT_OK, result); setResult(RESULT_OK, result);
} }
finish(); // show finish
vAnimator.setDisplayedChild(2);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// wait some 1000ms here, give the user time to appreciate the displayed finish
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// never mind
}
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
finish();
}
}.execute();
} }
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException { private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {

View File

@@ -148,6 +148,10 @@ public class ViewKeyActivity extends BaseNfcActivity implements
private String mFingerprint; private String mFingerprint;
private long mMasterKeyId; private long mMasterKeyId;
private byte[] mNfcFingerprints;
private String mNfcUserId;
private byte[] mNfcAid;
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -540,13 +544,17 @@ public class ViewKeyActivity extends BaseNfcActivity implements
} }
@Override @Override
protected void onNfcPerform() throws IOException { protected void doNfcInBackground() throws IOException {
final byte[] nfcFingerprints = nfcGetFingerprints(); mNfcFingerprints = nfcGetFingerprints();
final String nfcUserId = nfcGetUserId(); mNfcUserId = nfcGetUserId();
final byte[] nfcAid = nfcGetAid(); mNfcAid = nfcGetAid();
}
long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints); @Override
protected void onNfcPostExecute() throws IOException {
long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
try { try {
@@ -557,7 +565,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// if the master key of that key matches this one, just show the yubikey dialog // if the master key of that key matches this one, just show the yubikey dialog
if (KeyFormattingUtils.convertFingerprintToHex(candidateFp).equals(mFingerprint)) { if (KeyFormattingUtils.convertFingerprintToHex(candidateFp).equals(mFingerprint)) {
showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid); showYubiKeyFragment(mNfcFingerprints, mNfcUserId, mNfcAid);
return; return;
} }
@@ -570,9 +578,9 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Intent intent = new Intent( Intent intent = new Intent(
ViewKeyActivity.this, ViewKeyActivity.class); ViewKeyActivity.this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
@@ -586,15 +594,14 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public void onAction() { public void onAction() {
Intent intent = new Intent( Intent intent = new Intent(
ViewKeyActivity.this, CreateKeyActivity.class); ViewKeyActivity.this, CreateKeyActivity.class);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
}, R.string.snack_yubikey_import).show(); }, R.string.snack_yubikey_import).show();
} }
} }
public void showYubiKeyFragment( public void showYubiKeyFragment(

View File

@@ -30,6 +30,7 @@ import android.content.IntentFilter;
import android.nfc.NfcAdapter; import android.nfc.NfcAdapter;
import android.nfc.Tag; import android.nfc.Tag;
import android.nfc.tech.IsoDep; import android.nfc.tech.IsoDep;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.widget.Toast; import android.widget.Toast;
@@ -74,6 +75,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
private static final int TIMEOUT = 100000; private static final int TIMEOUT = 100000;
private byte[] mNfcFingerprints;
private String mNfcUserId;
private byte[] mNfcAid;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -91,28 +96,59 @@ public abstract class BaseNfcActivity extends BaseActivity {
* All new NFC Intents which are delivered to this activity are handled here * All new NFC Intents which are delivered to this activity are handled here
*/ */
@Override @Override
public void onNewIntent(Intent intent) { public void onNewIntent(final Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
try {
handleTagDiscoveredIntent(intent); // Actual NFC operations are executed in doInBackground to not block the UI thread
} catch (CardException e) { new AsyncTask<Void, Void, Exception>() {
handleNfcError(e); @Override
} catch (IOException e) { protected void onPreExecute() {
handleNfcError(e); super.onPreExecute();
} onNfcPreExecute();
}
@Override
protected Exception doInBackground(Void... params) {
try {
handleTagDiscoveredIntent(intent);
} catch (CardException e) {
return e;
} catch (IOException e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception exception) {
super.onPostExecute(exception);
if (exception != null) {
handleNfcError(exception);
return;
}
try {
onNfcPostExecute();
} catch (IOException e) {
handleNfcError(e);
}
}
}.execute();
} }
} }
public void handleNfcError(IOException e) { public void handleNfcError(Exception e) {
Log.e(Constants.TAG, "nfc error", e); Log.e(Constants.TAG, "nfc error", e);
Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show();
}
public void handleNfcError(CardException e) { short status;
Log.e(Constants.TAG, "card error", e); if (e instanceof CardException) {
status = ((CardException) e).getResponseCode();
short status = e.getResponseCode(); } else {
status = -1;
}
// When entering a PIN, a status of 63CX indicates X attempts remaining. // When entering a PIN, a status of 63CX indicates X attempts remaining.
if ((status & (short)0xFFF0) == 0x63C0) { if ((status & (short)0xFFF0) == 0x63C0) {
Notify.create(this, getString(R.string.error_pin, status & 0x000F), Style.WARN).show(); Notify.create(this, getString(R.string.error_pin, status & 0x000F), Style.WARN).show();
@@ -313,20 +349,25 @@ public abstract class BaseNfcActivity extends BaseActivity {
mPw1ValidatedForDecrypt = false; mPw1ValidatedForDecrypt = false;
mPw3Validated = false; mPw3Validated = false;
onNfcPerform(); doNfcInBackground();
mIsoDep.close(); mIsoDep.close();
mIsoDep = null; mIsoDep = null;
} }
protected void onNfcPerform() throws IOException { protected void onNfcPreExecute() {
}
final byte[] nfcFingerprints = nfcGetFingerprints(); protected void doNfcInBackground() throws IOException {
final String nfcUserId = nfcGetUserId(); mNfcFingerprints = nfcGetFingerprints();
final byte[] nfcAid = nfcGetAid(); mNfcUserId = nfcGetUserId();
mNfcAid = nfcGetAid();
}
final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints); protected void onNfcPostExecute() throws IOException {
final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
try { try {
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing( CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(
@@ -335,18 +376,17 @@ public abstract class BaseNfcActivity extends BaseActivity {
Intent intent = new Intent(this, ViewKeyActivity.class); Intent intent = new Intent(this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent); startActivity(intent);
} catch (PgpKeyNotFoundException e) { } catch (PgpKeyNotFoundException e) {
Intent intent = new Intent(this, CreateKeyActivity.class); Intent intent = new Intent(this, CreateKeyActivity.class);
intent.putExtra(CreateKeyActivity.EXTRA_NFC_AID, nfcAid); intent.putExtra(CreateKeyActivity.EXTRA_NFC_AID, mNfcAid);
intent.putExtra(CreateKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); intent.putExtra(CreateKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(CreateKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); intent.putExtra(CreateKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent); startActivity(intent);
} }
} }
/** Return the key id from application specific data stored on tag, or null /** Return the key id from application specific data stored on tag, or null
@@ -608,7 +648,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
* conformance to the card's requirements for key length. * conformance to the card's requirements for key length.
* *
* @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83. * @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83.
* @param newPinString The new PW1 or PW3. * @param newPin The new PW1 or PW3.
*/ */
public void nfcModifyPIN(int pw, byte[] newPin) throws IOException { public void nfcModifyPIN(int pw, byte[] newPin) throws IOException {
final int MAX_PW1_LENGTH_INDEX = 1; final int MAX_PW1_LENGTH_INDEX = 1;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 340 KiB

View File

@@ -1,35 +1,86 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content">
<include <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
android:id="@+id/toolbar_include" android:id="@+id/view_animator"
layout="@layout/toolbar_standalone" />
<LinearLayout
android:layout_below="@id/toolbar_include"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:animateLayoutChanges="true"
android:paddingLeft="16dp" android:inAnimation="@anim/fade_in"
android:paddingRight="16dp" android:measureAllChildren="false"
android:minHeight="?listPreferredItemHeightSmall"
android:outAnimation="@anim/fade_out"
android:paddingBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingBottom="16dp"> custom:initialView="0">
<TextView <LinearLayout
android:text="@string/nfc_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Large"
android:id="@+id/nfc_text"
android:gravity="center"
android:layout_gravity="center" />
<ImageView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/yubikey_phone" /> android:layout_below="@id/toolbar_include"
android:layout_gravity="center"
android:orientation="vertical">
</LinearLayout> <TextView
</RelativeLayout> android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nfc_text"
android:textAppearance="@android:style/TextAppearance.Medium" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:adjustViewBounds="true"
android:src="@drawable/yubikey_phone"
android:id="@+id/nfc_image"
android:background="@android:color/transparent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar_include"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nfc_wait"
android:textAppearance="@android:style/TextAppearance.Medium" />
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar_include"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nfc_finished"
android:textAppearance="@android:style/TextAppearance.Medium" />
</LinearLayout>
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
</LinearLayout>

View File

@@ -225,7 +225,9 @@
<string name="passphrase_for">"Enter password for '%s'"</string> <string name="passphrase_for">"Enter password for '%s'"</string>
<string name="pin_for">"Enter PIN for '%s'"</string> <string name="pin_for">"Enter PIN for '%s'"</string>
<string name="yubikey_pin_for">"Enter PIN to access YubiKey for '%s'"</string> <string name="yubikey_pin_for">"Enter PIN to access YubiKey for '%s'"</string>
<string name="nfc_text">"Hold YubiKey against the back of your device."</string> <string name="nfc_text">"Hold YubiKey against the NFC marker at the back of your device."</string>
<string name="nfc_wait">"Don't release the YubiKey yet!"</string>
<string name="nfc_finished">"Success"</string>
<string name="file_delete_confirmation_title">"Delete original files?"</string> <string name="file_delete_confirmation_title">"Delete original files?"</string>
<string name="file_delete_confirmation">"The following files will be deleted:%s"</string> <string name="file_delete_confirmation">"The following files will be deleted:%s"</string>
<string name="file_delete_successful">"%1$d out of %2$d files have been deleted.%3$s"</string> <string name="file_delete_successful">"%1$d out of %2$d files have been deleted.%3$s"</string>

View File

@@ -35,4 +35,9 @@
<!-- Layout for query suggestion rows --> <!-- Layout for query suggestion rows -->
<!--<item name="suggestionRowLayout">...</item>--> <!--<item name="suggestionRowLayout">...</item>-->
</style> </style>
<style name="KeychainTheme.DialogWithoutTitle" parent="@style/Theme.AppCompat.Light.Dialog.MinWidth">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources> </resources>