token-import: add ui for pin change and unlock
This commit is contained in:
parent
36bec236f4
commit
646940eb44
|
@ -108,7 +108,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
|
|||
/**
|
||||
* Override to do something when PIN is wrong, e.g., clear passphrases (UI thread)
|
||||
*/
|
||||
protected void onSecurityTokenPinError(String error) {
|
||||
protected void onSecurityTokenPinError(String error, SecurityTokenInfo tokeninfo) {
|
||||
onSecurityTokenError(error);
|
||||
}
|
||||
|
||||
|
@ -242,8 +242,16 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
|
|||
// https://github.com/Yubico/ykneo-openpgp/commit/90c2b91e86fb0e43ee234dd258834e75e3416410
|
||||
if ((status & (short) 0xFFF0) == 0x63C0) {
|
||||
int tries = status & 0x000F;
|
||||
|
||||
SecurityTokenInfo tokeninfo = null;
|
||||
try {
|
||||
tokeninfo = mSecurityTokenHelper.getTokenInfo();
|
||||
} catch (IOException e2) {
|
||||
// don't care
|
||||
}
|
||||
// hook to do something different when PIN is wrong
|
||||
onSecurityTokenPinError(getResources().getQuantityString(R.plurals.security_token_error_pin, tries, tries));
|
||||
onSecurityTokenPinError(
|
||||
getResources().getQuantityString(R.plurals.security_token_error_pin, tries, tries), tokeninfo);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -256,8 +264,15 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
|
|||
PW not checked (command not allowed), Secure messaging incorrect (checksum and/or cryptogram) */
|
||||
// NOTE: Used in ykneo-openpgp >= 1.0.11 for wrong PIN
|
||||
case 0x6982: {
|
||||
SecurityTokenInfo tokeninfo = null;
|
||||
try {
|
||||
tokeninfo = mSecurityTokenHelper.getTokenInfo();
|
||||
} catch (IOException e2) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
// hook to do something different when PIN is wrong
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_security_not_satisfied));
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_security_not_satisfied), tokeninfo);
|
||||
break;
|
||||
}
|
||||
/* OpenPGP Card Spec: Selected file in termination state */
|
||||
|
@ -270,14 +285,14 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
|
|||
// https://github.com/Yubico/ykneo-openpgp/commit/b49ce8241917e7c087a4dab7b2c755420ff4500f
|
||||
case 0x6700: {
|
||||
// hook to do something different when PIN is wrong
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_wrong_length));
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_wrong_length), null);
|
||||
break;
|
||||
}
|
||||
/* OpenPGP Card Spec: Incorrect parameters in the data field */
|
||||
// NOTE: Used in ykneo-openpgp >= 1.0.11 for too short PIN
|
||||
case 0x6A80: {
|
||||
// hook to do something different when PIN is wrong
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_bad_data));
|
||||
onSecurityTokenPinError(getString(R.string.security_token_error_bad_data), null);
|
||||
break;
|
||||
}
|
||||
/* OpenPGP Card Spec: Authentication method blocked, PW blocked (error counter zero) */
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package org.sufficientlysecure.keychain.ui.token;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnShowListener;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AlertDialog.Builder;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenContract.ManageSecurityTokenMvpPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
||||
|
||||
|
||||
class ChangePinDialogHelper {
|
||||
@CheckResult
|
||||
static AlertDialog createAdminPinDialog(Context context, final ManageSecurityTokenMvpPresenter presenter) {
|
||||
ContextThemeWrapper themedContext = ThemeChanger.getDialogThemeWrapper(context);
|
||||
|
||||
@SuppressLint("InflateParams") // it's a dialog, no root element
|
||||
View view = LayoutInflater.from(themedContext).inflate(R.layout.admin_pin_dialog, null, false);
|
||||
final EditText adminPin = (EditText) view.findViewById(R.id.admin_pin_current);
|
||||
final EditText newPin = (EditText) view.findViewById(R.id.pin_new);
|
||||
final EditText newPinRepeat = (EditText) view.findViewById(R.id.pin_new_repeat);
|
||||
|
||||
AlertDialog dialog = new Builder(themedContext)
|
||||
.setView(view)
|
||||
.setNegativeButton(R.string.button_cancel, null)
|
||||
.setPositiveButton(R.string.token_unlock_ok, null).create();
|
||||
dialog.setOnShowListener(new OnShowListener() {
|
||||
@Override
|
||||
public void onShow(final DialogInterface dialog) {
|
||||
((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
checkAndHandleInput(adminPin, newPin, newPinRepeat, dialog, presenter);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private static void checkAndHandleInput(EditText adminPinView, EditText newPinView, EditText newPinRepeatView,
|
||||
DialogInterface dialog, ManageSecurityTokenMvpPresenter presenter) {
|
||||
String adminPin = adminPinView.getText().toString();
|
||||
String newPin = newPinView.getText().toString();
|
||||
String newPinRepeat = newPinRepeatView.getText().toString();
|
||||
|
||||
if (adminPin.length() < 8) {
|
||||
adminPinView.setError(adminPinView.getContext().getString(R.string.token_error_admin_min8));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPin.length() < 6) {
|
||||
newPinView.setError(newPinView.getContext().getString(R.string.token_error_pin_min6));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newPin.equals(newPinRepeat)) {
|
||||
newPinRepeatView.setError(newPinRepeatView.getContext().getString(R.string.token_error_pin_repeat));
|
||||
return;
|
||||
}
|
||||
|
||||
dialog.dismiss();
|
||||
presenter.onInputAdminPin(adminPin, newPin);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui.token;
|
|||
import android.net.Uri;
|
||||
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
|
||||
import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenFragment.StatusLine;
|
||||
|
||||
|
||||
|
@ -31,7 +32,7 @@ class ManageSecurityTokenContract {
|
|||
|
||||
void onClickRetry();
|
||||
void onClickViewKey();
|
||||
void onClickViewLog();
|
||||
void onMenuClickViewLog();
|
||||
|
||||
void onClickImport();
|
||||
void onImportSuccess(OperationResult result);
|
||||
|
@ -41,6 +42,10 @@ class ManageSecurityTokenContract {
|
|||
void onPromoteError(OperationResult result);
|
||||
|
||||
|
||||
void onSecurityTokenChangePinSuccess(SecurityTokenInfo tokenInfo);
|
||||
|
||||
void onSecurityTokenChangePinCanceled(SecurityTokenInfo tokenInfo);
|
||||
|
||||
void onClickLoadFile();
|
||||
void onFileSelected(Uri fileUri);
|
||||
void onStoragePermissionGranted();
|
||||
|
@ -48,9 +53,14 @@ class ManageSecurityTokenContract {
|
|||
|
||||
void onClickResetToken();
|
||||
void onClickConfirmReset();
|
||||
void onSecurityTokenResetSuccess();
|
||||
void onSecurityTokenResetSuccess(SecurityTokenInfo tokenInfo);
|
||||
void onSecurityTokenResetCanceled(SecurityTokenInfo tokenInfo);
|
||||
|
||||
void onClickUnlockToken();
|
||||
void onMenuClickChangePin();
|
||||
void onInputAdminPin(String adminPin, String newPin);
|
||||
|
||||
void onClickUnlockTokenImpossible();
|
||||
}
|
||||
|
||||
interface ManageSecurityTokenMvpView {
|
||||
|
@ -74,9 +84,12 @@ class ManageSecurityTokenContract {
|
|||
|
||||
void showFileSelectDialog();
|
||||
void showConfirmResetDialog();
|
||||
void showAdminPinDialog();
|
||||
|
||||
void showDisplayLogActivity(OperationResult result);
|
||||
|
||||
void requestStoragePermission();
|
||||
|
||||
void showErrorCannotUnlock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AlertDialog.Builder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -41,8 +42,6 @@ import android.view.View.OnClickListener;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.sufficientlysecure.keychain.BuildConfig;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||
|
@ -65,7 +64,8 @@ import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper.AbstractCal
|
|||
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
|
||||
import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenContract.ManageSecurityTokenMvpPresenter;
|
||||
import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenContract.ManageSecurityTokenMvpView;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
|
||||
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator;
|
||||
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator.Status;
|
||||
|
@ -149,7 +149,9 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
view.findViewById(R.id.button_reset_token_2).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_reset_token_3).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_reset_token_4).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_reset_token_5).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_unlock).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_unlock_impossible).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_load_file).setOnClickListener(this);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
@ -175,7 +177,11 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.view_log: {
|
||||
presenter.onClickViewLog();
|
||||
presenter.onMenuClickViewLog();
|
||||
return true;
|
||||
}
|
||||
case R.id.change_pin: {
|
||||
presenter.onMenuClickChangePin();
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
|
@ -259,13 +265,14 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
|
||||
@Override
|
||||
public void showActionLocked(int attemptsLeft) {
|
||||
actionAnimator.setDisplayedChildId(R.id.token_layout_locked);
|
||||
if (attemptsLeft > 0) {
|
||||
actionAnimator.setDisplayedChildId(R.id.token_layout_locked);
|
||||
|
||||
String unlockAttemptsText = getResources().getQuantityString(
|
||||
R.plurals.token_unlock_attempts, attemptsLeft, attemptsLeft);
|
||||
unlockSubtitle.setText(unlockAttemptsText);
|
||||
} else {
|
||||
unlockSubtitle.setText(R.string.token_unlock_attempts_none);
|
||||
actionAnimator.setDisplayedChildId(R.id.token_layout_locked_hard);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,12 +336,23 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
.setPositiveButton(R.string.token_reset_confirm_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
presenter.onClickConfirmReset();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAdminPinDialog() {
|
||||
AlertDialog adminPinDialog = ChangePinDialogHelper.createAdminPinDialog(getContext(), presenter);
|
||||
|
||||
adminPinDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorCannotUnlock() {
|
||||
Notify.create(getActivity(), R.string.token_error_locked_indefinitely, Style.ERROR).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDisplayLogActivity(OperationResult result) {
|
||||
Intent intent = new Intent(getActivity(), LogDisplayActivity.class);
|
||||
|
@ -374,8 +392,22 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
break;
|
||||
}
|
||||
case REQUEST_CODE_RESET: {
|
||||
SecurityTokenInfo tokenInfo = data == null ? null :
|
||||
data.<SecurityTokenInfo>getParcelableExtra(SecurityTokenOperationActivity.RESULT_TOKEN_INFO);
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
presenter.onSecurityTokenResetSuccess();
|
||||
presenter.onSecurityTokenResetSuccess(tokenInfo);
|
||||
} else {
|
||||
presenter.onSecurityTokenResetCanceled(tokenInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_CHANGE_PIN: {
|
||||
SecurityTokenInfo tokenInfo = data == null ? null :
|
||||
data.<SecurityTokenInfo>getParcelableExtra(SecurityTokenOperationActivity.RESULT_TOKEN_INFO);
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
presenter.onSecurityTokenChangePinSuccess(tokenInfo);
|
||||
} else {
|
||||
presenter.onSecurityTokenChangePinCanceled(tokenInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -407,7 +439,8 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
case R.id.button_reset_token_1:
|
||||
case R.id.button_reset_token_2:
|
||||
case R.id.button_reset_token_3:
|
||||
case R.id.button_reset_token_4: {
|
||||
case R.id.button_reset_token_4:
|
||||
case R.id.button_reset_token_5: {
|
||||
presenter.onClickResetToken();
|
||||
break;
|
||||
}
|
||||
|
@ -416,6 +449,10 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
|||
presenter.onClickUnlockToken();
|
||||
break;
|
||||
}
|
||||
case R.id.button_unlock_impossible: {
|
||||
presenter.onClickUnlockTokenImpossible();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
|
||||
private final Context context;
|
||||
private final LoaderManager loaderManager;
|
||||
private final SecurityTokenInfo tokenInfo;
|
||||
|
||||
private SecurityTokenInfo tokenInfo;
|
||||
|
||||
|
||||
private ManageSecurityTokenMvpView view;
|
||||
|
@ -92,11 +93,28 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
continueSearch();
|
||||
}
|
||||
|
||||
private void resetAndContinueSearch() {
|
||||
checkedKeyStatus = false;
|
||||
searchedLocally = false;
|
||||
searchedAtUri = false;
|
||||
searchedKeyservers = false;
|
||||
|
||||
view.hideAction();
|
||||
view.resetStatusLines();
|
||||
continueSearch();
|
||||
}
|
||||
|
||||
private void continueSearch() {
|
||||
if (!checkedKeyStatus) {
|
||||
view.statusLineAdd(StatusLine.CHECK_KEY);
|
||||
delayPerformKeyCheck();
|
||||
return;
|
||||
boolean keyIsLocked = tokenInfo.getVerifyRetries() == 0;
|
||||
if (keyIsLocked) {
|
||||
// the "checking key status" is fake: we only do it if we already know the key is locked
|
||||
view.statusLineAdd(StatusLine.CHECK_KEY);
|
||||
delayPerformKeyCheck();
|
||||
return;
|
||||
} else {
|
||||
checkedKeyStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchedLocally) {
|
||||
|
@ -150,6 +168,30 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
view.showAdminPinDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMenuClickChangePin() {
|
||||
if (!checkedKeyStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokenInfo.getVerifyAdminRetries() == 0) {
|
||||
view.showErrorCannotUnlock();
|
||||
return;
|
||||
}
|
||||
|
||||
view.showAdminPinDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputAdminPin(String adminPin, String newPin) {
|
||||
view.operationChangePinSecurityToken(adminPin, newPin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClickUnlockTokenImpossible() {
|
||||
view.showErrorCannotUnlock();
|
||||
}
|
||||
|
||||
private LoaderCallbacks<KeyRetrievalResult> loaderCallbacks = new LoaderCallbacks<KeyRetrievalResult>() {
|
||||
@Override
|
||||
public Loader<KeyRetrievalResult> onCreateLoader(int id, Bundle args) {
|
||||
|
@ -272,13 +314,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
|
||||
@Override
|
||||
public void onClickRetry() {
|
||||
searchedLocally = false;
|
||||
searchedAtUri = false;
|
||||
searchedKeyservers = false;
|
||||
|
||||
view.hideAction();
|
||||
view.resetStatusLines();
|
||||
continueSearch();
|
||||
resetAndContinueSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -297,8 +333,31 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityTokenResetSuccess() {
|
||||
// TODO
|
||||
public void onSecurityTokenResetSuccess(SecurityTokenInfo tokenInfo) {
|
||||
this.tokenInfo = tokenInfo;
|
||||
resetAndContinueSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityTokenResetCanceled(SecurityTokenInfo tokenInfo) {
|
||||
if (tokenInfo != null) {
|
||||
this.tokenInfo = tokenInfo;
|
||||
resetAndContinueSearch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityTokenChangePinSuccess(SecurityTokenInfo tokenInfo) {
|
||||
this.tokenInfo = tokenInfo;
|
||||
resetAndContinueSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityTokenChangePinCanceled(SecurityTokenInfo tokenInfo) {
|
||||
if (tokenInfo != null) {
|
||||
this.tokenInfo = tokenInfo;
|
||||
resetAndContinueSearch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -340,7 +399,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onClickViewLog() {
|
||||
public void onMenuClickViewLog() {
|
||||
OperationResult result = new GenericOperationResult(GenericOperationResult.RESULT_OK, log);
|
||||
view.showDisplayLogActivity(result);
|
||||
}
|
||||
|
|
31
OpenKeychain/src/main/res/layout/admin_pin_dialog.xml
Normal file
31
OpenKeychain/src/main/res/layout/admin_pin_dialog.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp"
|
||||
tools:showIn="@layout/fake_dialog">
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/token_hint_admin_pin"
|
||||
android:id="@+id/admin_pin_current"
|
||||
android:inputType="numberPassword|textVisiblePassword" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/token_hint_new_pin"
|
||||
android:id="@+id/pin_new"
|
||||
android:inputType="numberPassword|textVisiblePassword" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/token_hint_new_pin_repeat"
|
||||
android:id="@+id/pin_new_repeat"
|
||||
android:inputType="numberPassword|textVisiblePassword" />
|
||||
|
||||
</LinearLayout>
|
|
@ -50,7 +50,7 @@
|
|||
android:inAnimation="@anim/fade_in_delayed"
|
||||
android:outAnimation="@anim/fade_out"
|
||||
android:clipChildren="false"
|
||||
custom:initialView="04">
|
||||
custom:initialView="05">
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -233,7 +233,7 @@
|
|||
android:textColor="@color/card_view_button"
|
||||
android:textAllCaps="true"
|
||||
android:textStyle="bold"
|
||||
android:text="Unlock using admin pin"
|
||||
android:text="@string/token_action_unlock"
|
||||
android:padding="0dp"
|
||||
android:minHeight="0dp"
|
||||
/>
|
||||
|
@ -265,6 +265,81 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/token_layout_locked_hard">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?listPreferredItemHeight"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Token is locked!"
|
||||
style="?android:textAppearanceLarge"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:id="@+id/button_unlock_impossible"
|
||||
android:background="?selectableItemBackground"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:tint="@color/md_grey_400"
|
||||
android:id="@+id/button_unlock_drawable_2"
|
||||
android:src="@drawable/ic_vpn_key_grey_24dp"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/button_unlock_drawable_2"
|
||||
android:layout_toRightOf="@+id/button_unlock_drawable_2"
|
||||
android:id="@+id/button_unlock_title_2"
|
||||
android:textColor="@color/md_grey_400"
|
||||
android:textAllCaps="true"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/token_action_unlock"
|
||||
android:padding="0dp"
|
||||
android:minHeight="0dp"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/button_unlock_drawable_2"
|
||||
android:layout_toRightOf="@+id/button_unlock_drawable_2"
|
||||
android:layout_below="@+id/button_unlock_title_2"
|
||||
android:textColor="@color/md_grey_400"
|
||||
android:text="@string/token_unlock_attempts_none"
|
||||
style="?android:textAppearanceSmall"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/button_reset_token_5"
|
||||
android:drawableLeft="@drawable/ic_bomb_24dp"
|
||||
android:drawableStart="@drawable/ic_bomb_24dp"
|
||||
android:drawablePadding="12dp"
|
||||
android:textColor="@color/android_red_dark"
|
||||
android:text="@string/token_status_reset"
|
||||
style="?borderlessButtonStyle"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
16
OpenKeychain/src/main/res/layout/fake_dialog.xml
Normal file
16
OpenKeychain/src/main/res/layout/fake_dialog.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<include layout="@layout/admin_pin_dialog" />
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
</FrameLayout>
|
|
@ -10,7 +10,7 @@
|
|||
android:measureAllChildren="false"
|
||||
android:minHeight="?listPreferredItemHeightSmall"
|
||||
android:outAnimation="@anim/fade_out"
|
||||
custom:initialView="3"
|
||||
custom:initialView="4"
|
||||
tools:showIn="@layout/security_token_operation_activity">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -126,4 +126,34 @@
|
|||
|
||||
</ScrollView>
|
||||
|
||||
<ScrollView
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/security_token_activity_4_error_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="24dp"
|
||||
android:textAppearance="@android:style/TextAppearance.Medium"
|
||||
android:textColor="@color/android_red_dark"
|
||||
tools:text="Error text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/security_token_activity_4_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="8dp"
|
||||
android:text="Back" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||
|
|
|
@ -8,4 +8,12 @@
|
|||
android:title="Debug / Token from Uri"
|
||||
android:id="@+id/menu_token_debug_uri"
|
||||
/>
|
||||
<item
|
||||
android:title="Debug / Locked Token"
|
||||
android:id="@+id/menu_token_debug_locked"
|
||||
/>
|
||||
<item
|
||||
android:title="Debug / Hard Locked Token"
|
||||
android:id="@+id/menu_token_debug_locked_hard"
|
||||
/>
|
||||
</menu>
|
|
@ -2,8 +2,13 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:title="View Log"
|
||||
android:title="@string/token_menu_view_log"
|
||||
android:id="@+id/view_log"
|
||||
app:showAsAction="never"
|
||||
/>
|
||||
<item
|
||||
android:title="@string/token_menu_change_pin"
|
||||
android:id="@+id/change_pin"
|
||||
app:showAsAction="never"
|
||||
/>
|
||||
</menu>
|
|
@ -1926,6 +1926,7 @@
|
|||
<string name="status_token_promote">Setting up key…</string>
|
||||
<string name="status_token_check">Checking key setup…</string>
|
||||
<string name="status_content_uri">Reading file…</string>
|
||||
|
||||
<string name="token_reset_confirm_title">Reset Security Token?</string>
|
||||
<string name="token_reset_confirm_message">This will irrecoverably delete the key stored on this Security Token. You will no longer be able to use this key for decryption! Are you sure?</string>
|
||||
<string name="token_reset_confirm_ok">Reset</string>
|
||||
|
@ -1938,11 +1939,24 @@
|
|||
<string name="token_status_import">Import</string>
|
||||
<string name="token_status_token_ok">Ready for use!</string>
|
||||
<string name="token_status_view_key">View Key</string>
|
||||
<string name="token_action_unlock">Unlock using admin pin</string>
|
||||
<string name="token_unlock_attempts_none">"No unlock attempts left"</string>
|
||||
<plurals name="token_unlock_attempts">
|
||||
<item quantity="one">"1 attempt left"</item>
|
||||
<item quantity="other">"%d attempts left"</item>
|
||||
</plurals>
|
||||
<string name="token_error_locked_indefinitely">Too many reset attempts. Token is locked irrecoverably!</string>
|
||||
|
||||
<string name="token_menu_change_pin">Change Pin</string>
|
||||
<string name="token_menu_view_log">View Log</string>
|
||||
|
||||
<string name="token_unlock_ok">Unlock</string>
|
||||
<string name="token_hint_admin_pin">Admin Pin</string>
|
||||
<string name="token_hint_new_pin">New Pin</string>
|
||||
<string name="token_hint_new_pin_repeat">New Pin (repeat)</string>
|
||||
<string name="token_error_admin_min8">Admin pin must be 8 characters or longer!</string>
|
||||
<string name="token_error_pin_min6">New pin must be 6 characters or longer!</string>
|
||||
<string name="token_error_pin_repeat">Doesn\'t match pin!</string>
|
||||
|
||||
<string name="msg_ret_curi_error_io">"Error reading data!"</string>
|
||||
<string name="msg_ret_curi_error_no_match">"No matching key found"</string>
|
||||
|
|
Loading…
Reference in a new issue