Files
app_Settings/src/com/android/settings/fingerprint/FingerprintRemoveSidecar.java
Charles He 7569bb1881 Properly remove fingerprints when removing device lock.
When strong auth (PIN, password, or pattern) is removed from a user,
fingerprints enrolled for that user should also be removed. Then, if the
user has a work profile guarded by a unified work challenge, the work
profile's fingerprints should also be removed.

Previously, when removing the fingerprints of the current user,
ChooseLockGeneric checked the finger id of the onRemovalSucceeded() and
onRemovalError() callbacks, and assumed the removal had completed when
the id was 0. Only after this would it initiate the removal of work
profile fingerprints, if any.

However, the finger id is actually non-zero even for the user's last
fingerprint. This means the work profile fingerprints (under unified
challenge) were never removed. Another more visible symptom was that
when the user removed the device lock by choosing "None" or "Swipe" in
ChooseLockGeneric, the activity failed to exit, since finish() is called
only at the end of the removal flow which was not executed.

In this CL, we check the number of remaining fingerprints instead of
relying on the finger id, thus allowing the removal flow to complete and
the activity to finish().

Bug: 37938345
Test: manual, both with and without work profile
Test: make SettingsRoboTests
Change-Id: Ic04fd01177ad6d4a061023a4b6889af585f8f2b7
2017-05-16 23:40:38 +01:00

150 lines
4.8 KiB
Java

/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.fingerprint;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.os.UserHandle;
import java.util.Queue;
import java.util.LinkedList;
import android.util.Log;
/**
* Sidecar fragment to handle the state around fingerprint removal.
*/
public class FingerprintRemoveSidecar extends InstrumentedPreferenceFragment {
private static final String TAG = "FingerprintRemoveSidecar";
private Listener mListener;
private Fingerprint mFingerprintRemoving;
private Queue<Object> mFingerprintsRemoved;
FingerprintManager mFingerprintManager;
private class RemovalError {
Fingerprint fingerprint;
int errMsgId;
CharSequence errString;
public RemovalError(Fingerprint fingerprint, int errMsgId, CharSequence errString) {
this.fingerprint = fingerprint;
this.errMsgId = errMsgId;
this.errString = errString;
}
}
private FingerprintManager.RemovalCallback
mRemoveCallback = new FingerprintManager.RemovalCallback() {
@Override
public void onRemovalSucceeded(Fingerprint fingerprint, int remaining) {
if (mListener != null) {
mListener.onRemovalSucceeded(fingerprint);
} else {
mFingerprintsRemoved.add(fingerprint);
};
mFingerprintRemoving = null;
}
@Override
public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onRemovalError(fp, errMsgId, errString);
} else {
mFingerprintsRemoved.add(new RemovalError(fp, errMsgId, errString));
}
mFingerprintRemoving = null;
}
};
public void startRemove(Fingerprint fingerprint, int userId) {
if (mFingerprintRemoving != null) {
Log.e(TAG, "Remove already in progress");
return;
}
if (userId != UserHandle.USER_NULL) {
mFingerprintManager.setActiveUser(userId);
}
mFingerprintRemoving = fingerprint;
mFingerprintManager.remove(fingerprint, userId, mRemoveCallback);;
}
public FingerprintRemoveSidecar() {
mFingerprintsRemoved = new LinkedList<>();
}
public void setFingerprintManager(FingerprintManager fingerprintManager) {
mFingerprintManager = fingerprintManager;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
}
public void setListener(Listener listener) {
if (mListener == null && listener != null) {
while (!mFingerprintsRemoved.isEmpty()) {
Object o = mFingerprintsRemoved.poll();
if (o instanceof Fingerprint) {
listener.onRemovalSucceeded((Fingerprint)o);
} else if (o instanceof RemovalError) {
RemovalError e = (RemovalError) o;
listener.onRemovalError(e.fingerprint, e.errMsgId, e.errString);
}
}
}
mListener = listener;
}
public interface Listener {
void onRemovalSucceeded(Fingerprint fingerprint);
void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
}
final boolean isRemovingFingerprint(int fid) {
return inProgress() && mFingerprintRemoving.getFingerId() == fid;
}
final boolean inProgress() {
return mFingerprintRemoving != null;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_REMOVE_SIDECAR;
}
}