token-import: show unlock option for locked keys
This commit is contained in:
parent
768abb3074
commit
4d0a686220
|
@ -49,6 +49,8 @@ class ManageSecurityTokenContract {
|
||||||
void onClickResetToken();
|
void onClickResetToken();
|
||||||
void onClickConfirmReset();
|
void onClickConfirmReset();
|
||||||
void onSecurityTokenResetSuccess();
|
void onSecurityTokenResetSuccess();
|
||||||
|
|
||||||
|
void onClickUnlockToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ManageSecurityTokenMvpView {
|
interface ManageSecurityTokenMvpView {
|
||||||
|
@ -60,6 +62,7 @@ class ManageSecurityTokenContract {
|
||||||
void showActionImport();
|
void showActionImport();
|
||||||
void showActionViewKey();
|
void showActionViewKey();
|
||||||
void showActionRetryOrFromFile();
|
void showActionRetryOrFromFile();
|
||||||
|
void showActionLocked(int unlockAttempts);
|
||||||
void hideAction();
|
void hideAction();
|
||||||
|
|
||||||
void operationImportKey(byte[] importKeyData);
|
void operationImportKey(byte[] importKeyData);
|
||||||
|
|
|
@ -81,6 +81,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
||||||
ManageSecurityTokenMvpPresenter presenter;
|
ManageSecurityTokenMvpPresenter presenter;
|
||||||
private ViewGroup statusLayoutGroup;
|
private ViewGroup statusLayoutGroup;
|
||||||
private ToolableViewAnimator actionAnimator;
|
private ToolableViewAnimator actionAnimator;
|
||||||
|
private TextView unlockSubtitle;
|
||||||
|
|
||||||
ImportKeyringParcel currentImportKeyringParcel;
|
ImportKeyringParcel currentImportKeyringParcel;
|
||||||
PromoteKeyringParcel currentPromoteKeyringParcel;
|
PromoteKeyringParcel currentPromoteKeyringParcel;
|
||||||
|
@ -136,6 +137,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
||||||
|
|
||||||
statusLayoutGroup = (ViewGroup) view.findViewById(R.id.status_indicator_layout);
|
statusLayoutGroup = (ViewGroup) view.findViewById(R.id.status_indicator_layout);
|
||||||
actionAnimator = (ToolableViewAnimator) view.findViewById(R.id.action_animator);
|
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_import).setOnClickListener(this);
|
||||||
view.findViewById(R.id.button_view_key).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_1).setOnClickListener(this);
|
||||||
view.findViewById(R.id.button_reset_token_2).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_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);
|
view.findViewById(R.id.button_load_file).setOnClickListener(this);
|
||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
@ -250,6 +254,18 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
||||||
actionAnimator.setDisplayedChildId(R.id.token_layout_not_found);
|
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
|
@Override
|
||||||
public void hideAction() {
|
public void hideAction() {
|
||||||
actionAnimator.setDisplayedChild(0);
|
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_1:
|
||||||
case R.id.button_reset_token_2:
|
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();
|
presenter.onClickResetToken();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case R.id.button_unlock: {
|
||||||
|
presenter.onClickUnlockToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,6 +448,7 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
enum StatusLine {
|
enum StatusLine {
|
||||||
|
CHECK_KEY (R.string.status_check_key),
|
||||||
SEARCH_LOCAL (R.string.status_search_local),
|
SEARCH_LOCAL (R.string.status_search_local),
|
||||||
SEARCH_URI (R.string.status_search_uri),
|
SEARCH_URI (R.string.status_search_uri),
|
||||||
SEARCH_KEYSERVER (R.string.status_search_keyserver),
|
SEARCH_KEYSERVER (R.string.status_search_keyserver),
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui.token;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
@ -55,6 +56,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
||||||
|
|
||||||
private ManageSecurityTokenMvpView view;
|
private ManageSecurityTokenMvpView view;
|
||||||
|
|
||||||
|
private boolean checkedKeyStatus;
|
||||||
private boolean searchedLocally;
|
private boolean searchedLocally;
|
||||||
private boolean searchedAtUri;
|
private boolean searchedAtUri;
|
||||||
private boolean searchedKeyservers;
|
private boolean searchedKeyservers;
|
||||||
|
@ -80,7 +82,7 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreated() {
|
public void onActivityCreated() {
|
||||||
if (!searchedLocally || !searchedAtUri || !searchedKeyservers) {
|
if (!checkedKeyStatus || !searchedLocally || !searchedAtUri || !searchedKeyservers) {
|
||||||
continueSearch();
|
continueSearch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +93,12 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void continueSearch() {
|
private void continueSearch() {
|
||||||
|
if (!checkedKeyStatus) {
|
||||||
|
view.statusLineAdd(StatusLine.CHECK_KEY);
|
||||||
|
delayPerformKeyCheck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!searchedLocally) {
|
if (!searchedLocally) {
|
||||||
view.statusLineAdd(StatusLine.SEARCH_LOCAL);
|
view.statusLineAdd(StatusLine.SEARCH_LOCAL);
|
||||||
loaderManager.restartLoader(LOADER_LOCAL, null, loaderCallbacks);
|
loaderManager.restartLoader(LOADER_LOCAL, null, loaderCallbacks);
|
||||||
|
@ -112,6 +120,36 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
|
||||||
view.showActionRetryOrFromFile();
|
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>() {
|
private LoaderCallbacks<KeyRetrievalResult> loaderCallbacks = new LoaderCallbacks<KeyRetrievalResult>() {
|
||||||
@Override
|
@Override
|
||||||
public Loader<KeyRetrievalResult> onCreateLoader(int id, Bundle args) {
|
public Loader<KeyRetrievalResult> onCreateLoader(int id, Bundle args) {
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
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="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
android:inAnimation="@anim/fade_in_delayed"
|
android:inAnimation="@anim/fade_in_delayed"
|
||||||
android:outAnimation="@anim/fade_out"
|
android:outAnimation="@anim/fade_out"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
custom:initialView="01">
|
custom:initialView="04">
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -190,6 +191,80 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</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>
|
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -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">"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 "%s" network, then scan again."</string>
|
<string name="transfer_error_wifi_text_instructions_ssid">"Make sure you are on the "%s" 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_local">Searching in key list…</string>
|
||||||
<string name="status_search_uri">Searching at token Uri…</string>
|
<string name="status_search_uri">Searching at token Uri…</string>
|
||||||
<string name="status_search_keyserver">Searching on keyservers…</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_import">Import</string>
|
||||||
<string name="token_status_token_ok">Ready for use!</string>
|
<string name="token_status_token_ok">Ready for use!</string>
|
||||||
<string name="token_status_view_key">View Key</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_io">"Error reading data!"</string>
|
||||||
<string name="msg_ret_curi_error_no_match">"No matching key found"</string>
|
<string name="msg_ret_curi_error_no_match">"No matching key found"</string>
|
||||||
|
|
Loading…
Reference in a new issue