Improve delete fingerprint UI.

- Make fingerprint preference use two_target preference
- And add a delete button as secondary target
- Remove delete fingerint code from RenameDeleteDialog, and move to new
  DeleteFingerprintDialog
- Some code cleanup
- Tests

Change-Id: I49d9c7d1d03497f07c7e20a805f23e6da934f587
Fix: 37783186
Test: make RunSettingsRoboTests
This commit is contained in:
Fan Zhang
2017-06-19 14:40:23 -07:00
parent 326c91c8b5
commit 8a1fd388fd
5 changed files with 327 additions and 73 deletions

View File

@@ -36,6 +36,7 @@ import android.os.CancellationSignal;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
@@ -48,7 +49,6 @@ import android.text.SpannableStringBuilder;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
@@ -66,6 +66,7 @@ import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.TwoTargetPreference;
import com.android.settingslib.widget.FooterPreference;
import java.util.HashMap;
@@ -127,7 +128,7 @@ public class FingerprintSettings extends SubSettings {
}
public static class FingerprintSettingsFragment extends SettingsPreferenceFragment
implements OnPreferenceChangeListener {
implements OnPreferenceChangeListener, FingerprintPreference.OnDeleteClickListener {
private static final int MAX_RETRY_ATTEMPTS = 20;
private static final int RESET_HIGHLIGHT_DELAY_MS = 500;
@@ -173,7 +174,7 @@ public class FingerprintSettings extends SubSettings {
@Override
public void onAuthenticationFailed() {
mHandler.obtainMessage(MSG_FINGER_AUTH_FAIL).sendToTarget();
};
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
@@ -195,6 +196,7 @@ public class FingerprintSettings extends SubSettings {
fingerprint.getFingerId(), 0).sendToTarget();
updateDialog();
}
public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
final Activity activity = getActivity();
if (activity != null) {
@@ -202,11 +204,12 @@ public class FingerprintSettings extends SubSettings {
}
updateDialog();
}
private void updateDialog() {
RenameDeleteDialog renameDeleteDialog = (RenameDeleteDialog)getFragmentManager().
findFragmentByTag(RenameDeleteDialog.class.getName());
if (renameDeleteDialog != null) {
renameDeleteDialog.enableDelete();
RenameDialog renameDialog = (RenameDialog) getFragmentManager().
findFragmentByTag(RenameDialog.class.getName());
if (renameDialog != null) {
renameDialog.enableDelete();
}
}
};
@@ -236,7 +239,7 @@ public class FingerprintSettings extends SubSettings {
}
break;
}
};
}
};
private void stopFingerprint() {
@@ -310,10 +313,10 @@ public class FingerprintSettings extends SubSettings {
mRemovalSidecar.setFingerprintManager(mFingerprintManager);
mRemovalSidecar.setListener(mRemovalListener);
RenameDeleteDialog renameDeleteDialog = (RenameDeleteDialog)getFragmentManager().
findFragmentByTag(RenameDeleteDialog.class.getName());
if (renameDeleteDialog != null) {
renameDeleteDialog.setDeleteInProgress(mRemovalSidecar.inProgress());
RenameDialog renameDialog = (RenameDialog) getFragmentManager().
findFragmentByTag(RenameDialog.class.getName());
if (renameDialog != null) {
renameDialog.setDeleteInProgress(mRemovalSidecar.inProgress());
}
mFingerprintsRenaming = new HashMap<Integer, String>();
@@ -380,7 +383,8 @@ public class FingerprintSettings extends SubSettings {
final int fingerprintCount = items.size();
for (int i = 0; i < fingerprintCount; i++) {
final Fingerprint item = items.get(i);
FingerprintPreference pref = new FingerprintPreference(root.getContext());
FingerprintPreference pref = new FingerprintPreference(root.getContext(),
this /* onDeleteClickListener */);
pref.setKey(genKey(item.getFingerId()));
pref.setTitle(item.getName());
pref.setFingerprint(item);
@@ -471,14 +475,40 @@ public class FingerprintSettings extends SubSettings {
} else if (pref instanceof FingerprintPreference) {
FingerprintPreference fpref = (FingerprintPreference) pref;
final Fingerprint fp = fpref.getFingerprint();
showRenameDeleteDialog(fp);
return super.onPreferenceTreeClick(pref);
showRenameDialog(fp);
}
return true;
return super.onPreferenceTreeClick(pref);
}
private void showRenameDeleteDialog(final Fingerprint fp) {
RenameDeleteDialog renameDeleteDialog = new RenameDeleteDialog();
@Override
public void onDeleteClick(FingerprintPreference p) {
final boolean hasMultipleFingerprint =
mFingerprintManager.getEnrolledFingerprints(mUserId).size() > 1;
final Fingerprint fp = p.getFingerprint();
if (hasMultipleFingerprint) {
if (mRemovalSidecar.inProgress()) {
Log.d(TAG, "Fingerprint delete in progress, skipping");
return;
}
DeleteFingerprintDialog.newInstance(fp, this /* target */)
.show(getFragmentManager(), DeleteFingerprintDialog.class.getName());
} else {
ConfirmLastDeleteDialog lastDeleteDialog = new ConfirmLastDeleteDialog();
final boolean isProfileChallengeUser =
UserManager.get(getContext()).isManagedProfile(mUserId);
final Bundle args = new Bundle();
args.putParcelable("fingerprint", fp);
args.putBoolean("isProfileChallengeUser", isProfileChallengeUser);
lastDeleteDialog.setArguments(args);
lastDeleteDialog.setTargetFragment(this, 0);
lastDeleteDialog.show(getFragmentManager(),
ConfirmLastDeleteDialog.class.getName());
}
}
private void showRenameDialog(final Fingerprint fp) {
RenameDialog renameDialog = new RenameDialog();
Bundle args = new Bundle();
if (mFingerprintsRenaming.containsKey(fp.getFingerId())) {
final Fingerprint f = new Fingerprint(mFingerprintsRenaming.get(fp.getFingerId()),
@@ -487,10 +517,10 @@ public class FingerprintSettings extends SubSettings {
} else {
args.putParcelable("fingerprint", fp);
}
renameDeleteDialog.setDeleteInProgress(mRemovalSidecar.inProgress());
renameDeleteDialog.setArguments(args);
renameDeleteDialog.setTargetFragment(this, 0);
renameDeleteDialog.show(getFragmentManager(), RenameDeleteDialog.class.getName());
renameDialog.setDeleteInProgress(mRemovalSidecar.inProgress());
renameDialog.setArguments(args);
renameDialog.setTargetFragment(this, 0);
renameDialog.show(getFragmentManager(), RenameDialog.class.getName());
}
@Override
@@ -598,7 +628,8 @@ public class FingerprintSettings extends SubSettings {
}
}
private void deleteFingerPrint(Fingerprint fingerPrint) {
@VisibleForTesting
void deleteFingerPrint(Fingerprint fingerPrint) {
mRemovalSidecar.startRemove(fingerPrint, mUserId);
String name = genKey(fingerPrint.getFingerId());
Preference prefToRemove = findPreference(name);
@@ -622,7 +653,60 @@ public class FingerprintSettings extends SubSettings {
}
};
public static class RenameDeleteDialog extends InstrumentedDialogFragment {
public static class DeleteFingerprintDialog extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
private static final String KEY_FINGERPRINT = "fingerprint";
private Fingerprint mFp;
private AlertDialog mAlertDialog;
public static DeleteFingerprintDialog newInstance(Fingerprint fp,
FingerprintSettingsFragment target) {
final DeleteFingerprintDialog dialog = new DeleteFingerprintDialog();
final Bundle bundle = new Bundle();
bundle.putParcelable(KEY_FINGERPRINT, fp);
dialog.setArguments(bundle);
dialog.setTargetFragment(target, 0 /* requestCode */);
return dialog;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_FINGERPINT_EDIT;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mFp = getArguments().getParcelable(KEY_FINGERPRINT);
final String title = getString(R.string.fingerprint_delete_title, mFp.getName());
mAlertDialog = new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(R.string.fingerprint_delete_message)
.setPositiveButton(
R.string.security_settings_fingerprint_enroll_dialog_delete,
this /* onClickListener */)
.setNegativeButton(R.string.cancel, null /* onClickListener */)
.create();
return mAlertDialog;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
final int fingerprintId = mFp.getFingerId();
Log.v(TAG, "Removing fpId=" + fingerprintId);
mMetricsFeatureProvider.action(getContext(),
MetricsEvent.ACTION_FINGERPRINT_DELETE,
fingerprintId);
FingerprintSettingsFragment parent
= (FingerprintSettingsFragment) getTargetFragment();
parent.deleteFingerPrint(mFp);
}
}
}
public static class RenameDialog extends InstrumentedDialogFragment {
private Fingerprint mFp;
private EditText mDialogTextField;
@@ -636,6 +720,7 @@ public class FingerprintSettings extends SubSettings {
public void setDeleteInProgress(boolean deleteInProgress) {
mDeleteInProgress = deleteInProgress;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mFp = getArguments().getParcelable("fingerprint");
@@ -654,10 +739,8 @@ public class FingerprintSettings extends SubSettings {
final String newName =
mDialogTextField.getText().toString();
final CharSequence name = mFp.getName();
if (!newName.equals(name)) {
if (DEBUG) {
Log.v(TAG, "rename " + name + " to " + newName);
}
if (!TextUtils.equals(newName, name)) {
Log.d(TAG, "rename " + name + " to " + newName);
mMetricsFeatureProvider.action(getContext(),
MetricsEvent.ACTION_FINGERPRINT_RENAME,
mFp.getFingerId());
@@ -670,14 +753,6 @@ public class FingerprintSettings extends SubSettings {
dialog.dismiss();
}
})
.setNegativeButton(
R.string.security_settings_fingerprint_enroll_dialog_delete,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onDeleteClick(dialog);
}
})
.create();
mAlertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
@@ -711,29 +786,6 @@ public class FingerprintSettings extends SubSettings {
}
}
private void onDeleteClick(DialogInterface dialog) {
if (DEBUG) Log.v(TAG, "Removing fpId=" + mFp.getFingerId());
mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_DELETE,
mFp.getFingerId());
FingerprintSettingsFragment parent
= (FingerprintSettingsFragment) getTargetFragment();
final boolean isProfileChallengeUser =
UserManager.get(getContext()).isManagedProfile(parent.mUserId);
if (parent.mFingerprintManager.getEnrolledFingerprints(parent.mUserId).size() > 1) {
parent.deleteFingerPrint(mFp);
} else {
ConfirmLastDeleteDialog lastDeleteDialog = new ConfirmLastDeleteDialog();
Bundle args = new Bundle();
args.putParcelable("fingerprint", mFp);
args.putBoolean("isProfileChallengeUser", isProfileChallengeUser);
lastDeleteDialog.setArguments(args);
lastDeleteDialog.setTargetFragment(getTargetFragment(), 0);
lastDeleteDialog.show(getFragmentManager(),
ConfirmLastDeleteDialog.class.getName());
}
dialog.dismiss();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -794,27 +846,26 @@ public class FingerprintSettings extends SubSettings {
}
}
public static class FingerprintPreference extends Preference {
public static class FingerprintPreference extends TwoTargetPreference {
private final OnDeleteClickListener mOnDeleteClickListener;
private Fingerprint mFingerprint;
private View mView;
private View mDeleteView;
public FingerprintPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public FingerprintPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
public interface OnDeleteClickListener {
void onDeleteClick(FingerprintPreference p);
}
public FingerprintPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FingerprintPreference(Context context) {
public FingerprintPreference(Context context, OnDeleteClickListener onDeleteClickListener) {
super(context);
mOnDeleteClickListener = onDeleteClickListener;
}
public View getView() { return mView; }
public View getView() {
return mView;
}
public void setFingerprint(Fingerprint item) {
mFingerprint = item;
@@ -824,12 +875,26 @@ public class FingerprintSettings extends SubSettings {
return mFingerprint;
}
@Override
protected int getSecondTargetResId() {
return R.layout.preference_widget_delete;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
mView = view.itemView;
mDeleteView = view.itemView.findViewById(R.id.delete_button);
mDeleteView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnDeleteClickListener != null) {
mOnDeleteClickListener.onDeleteClick(FingerprintPreference.this);
}
}
});
}
};
}
private static class LearnMoreSpan extends URLSpan {