token-import: show unlock option for locked keys

This commit is contained in:
Vincent Breitmoser 2017-09-06 03:53:54 +02:00
parent 768abb3074
commit 4d0a686220
5 changed files with 149 additions and 4 deletions

View file

@ -49,6 +49,8 @@ class ManageSecurityTokenContract {
void onClickResetToken();
void onClickConfirmReset();
void onSecurityTokenResetSuccess();
void onClickUnlockToken();
}
interface ManageSecurityTokenMvpView {
@ -60,6 +62,7 @@ class ManageSecurityTokenContract {
void showActionImport();
void showActionViewKey();
void showActionRetryOrFromFile();
void showActionLocked(int unlockAttempts);
void hideAction();
void operationImportKey(byte[] importKeyData);

View file

@ -81,6 +81,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
ManageSecurityTokenMvpPresenter presenter;
private ViewGroup statusLayoutGroup;
private ToolableViewAnimator actionAnimator;
private TextView unlockSubtitle;
ImportKeyringParcel currentImportKeyringParcel;
PromoteKeyringParcel currentPromoteKeyringParcel;
@ -136,6 +137,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
statusLayoutGroup = (ViewGroup) view.findViewById(R.id.status_indicator_layout);
actionAnimator = (ToolableViewAnimator) view.findViewById(R.id.action_animator);
unlockSubtitle = (TextView) view.findViewById(R.id.button_unlock_subtitle);
view.findViewById(R.id.button_import).setOnClickListener(this);
view.findViewById(R.id.button_view_key).setOnClickListener(this);
@ -143,6 +145,8 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
view.findViewById(R.id.button_reset_token_1).setOnClickListener(this);
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_unlock).setOnClickListener(this);
view.findViewById(R.id.button_load_file).setOnClickListener(this);
setHasOptionsMenu(true);
@ -250,6 +254,18 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
actionAnimator.setDisplayedChildId(R.id.token_layout_not_found);
}
@Override
public void showActionLocked(int attemptsLeft) {
actionAnimator.setDisplayedChildId(R.id.token_layout_locked);
if (attemptsLeft > 0) {
String unlockAttemptsText = getResources().getQuantityString(
R.plurals.token_unlock_attempts, attemptsLeft, attemptsLeft);
unlockSubtitle.setText(unlockAttemptsText);
} else {
unlockSubtitle.setText(R.string.token_unlock_attempts_none);
}
}
@Override
public void hideAction() {
actionAnimator.setDisplayedChild(0);
@ -378,10 +394,16 @@ 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_3:
case R.id.button_reset_token_4: {
presenter.onClickResetToken();
break;
}
case R.id.button_unlock: {
presenter.onClickUnlockToken();
break;
}
}
}
@ -426,6 +448,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
}, null);
enum StatusLine {
CHECK_KEY (R.string.status_check_key),
SEARCH_LOCAL (R.string.status_search_local),
SEARCH_URI (R.string.status_search_uri),
SEARCH_KEYSERVER (R.string.status_search_keyserver),

View file

@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui.token;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
@ -55,6 +56,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
private ManageSecurityTokenMvpView view;
private boolean checkedKeyStatus;
private boolean searchedLocally;
private boolean searchedAtUri;
private boolean searchedKeyservers;
@ -80,7 +82,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
@Override
public void onActivityCreated() {
if (!searchedLocally || !searchedAtUri || !searchedKeyservers) {
if (!checkedKeyStatus || !searchedLocally || !searchedAtUri || !searchedKeyservers) {
continueSearch();
}
}
@ -91,6 +93,12 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
}
private void continueSearch() {
if (!checkedKeyStatus) {
view.statusLineAdd(StatusLine.CHECK_KEY);
delayPerformKeyCheck();
return;
}
if (!searchedLocally) {
view.statusLineAdd(StatusLine.SEARCH_LOCAL);
loaderManager.restartLoader(LOADER_LOCAL, null, loaderCallbacks);
@ -112,6 +120,36 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
view.showActionRetryOrFromFile();
}
private void delayPerformKeyCheck() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
performKeyCheck();
}
}, 1000);
}
private void performKeyCheck() {
boolean isLocked = tokenInfo.getVerifyRetries() == 0;
if (!isLocked) {
view.statusLineOk();
checkedKeyStatus = true;
continueSearch();
return;
}
view.statusLineError();
int unlockAttemptsLeft = tokenInfo.getVerifyAdminRetries();
view.showActionLocked(unlockAttemptsLeft);
}
@Override
public void onClickUnlockToken() {
// TODO
}
private LoaderCallbacks<KeyRetrievalResult> loaderCallbacks = new LoaderCallbacks<KeyRetrievalResult>() {
@Override
public Loader<KeyRetrievalResult> onCreateLoader(int id, Bundle args) {

View file

@ -2,7 +2,8 @@
<ScrollView 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_height="match_parent">
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
@ -49,7 +50,7 @@
android:inAnimation="@anim/fade_in_delayed"
android:outAnimation="@anim/fade_out"
android:clipChildren="false"
custom:initialView="01">
custom:initialView="04">
<Space
android:layout_width="wrap_content"
@ -190,6 +191,80 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/token_layout_locked">
<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"
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:id="@+id/button_unlock_drawable"
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"
android:layout_toRightOf="@+id/button_unlock_drawable"
android:id="@+id/button_unlock_title"
android:textColor="@color/card_view_button"
android:textAllCaps="true"
android:textStyle="bold"
android:text="Unlock using admin pin"
android:padding="0dp"
android:minHeight="0dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/button_unlock_drawable"
android:layout_toRightOf="@+id/button_unlock_drawable"
android:layout_below="@+id/button_unlock_title"
android:id="@+id/button_unlock_subtitle"
tools:text="3 attempts left"
style="?android:textAppearanceSmall"
/>
</RelativeLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button_reset_token_4"
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>

View file

@ -1918,6 +1918,7 @@
<string name="transfer_error_wifi_text_instructions">"Make sure you are on the same network, then scan again."</string>
<string name="transfer_error_wifi_text_instructions_ssid">"Make sure you are on the &quot;%s&quot; network, then scan again."</string>
<string name="status_check_key">Checking key status…</string>
<string name="status_search_local">Searching in key list…</string>
<string name="status_search_uri">Searching at token Uri…</string>
<string name="status_search_keyserver">Searching on keyservers…</string>
@ -1937,6 +1938,11 @@
<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_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="msg_ret_curi_error_io">"Error reading data!"</string>
<string name="msg_ret_curi_error_no_match">"No matching key found"</string>