Merge "Support battery usage chart start index label is the detailed last full charge time" into udc-dev
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index f0d0350..9fc8a1f 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -80,5 +80,6 @@
<com.android.settingslib.widget.FooterPreference
android:key="security_face_footer"
+ settings:searchable="false"
settings:controller="com.android.settings.biometrics.face.FaceSettingsFooterPreferenceController" />
</PreferenceScreen>
diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
index 32d3a32..2d0744b 100644
--- a/src/com/android/settings/biometrics/BiometricNavigationUtils.java
+++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
@@ -26,6 +26,9 @@
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.Nullable;
+
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settingslib.RestrictedLockUtils;
@@ -49,15 +52,23 @@
*
* @param className The class name of Settings screen to launch.
* @param extras Extras to put into the launching {@link Intent}.
+ * @param launcher Launcher to launch activity if non-quiet mode
* @return true if the Settings screen is launching.
*/
- public boolean launchBiometricSettings(Context context, String className, Bundle extras) {
+ public boolean launchBiometricSettings(Context context, String className, Bundle extras,
+ @Nullable ActivityResultLauncher<Intent> launcher) {
final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
if (quietModeDialogIntent != null) {
context.startActivity(quietModeDialogIntent);
return false;
}
- context.startActivity(getSettingsPageIntent(className, extras));
+
+ final Intent settingsPageIntent = getSettingsPageIntent(className, extras);
+ if (launcher != null) {
+ launcher.launch(settingsPageIntent);
+ } else {
+ context.startActivity(settingsPageIntent);
+ }
return true;
}
diff --git a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
index 76a23a5..2f9ae6b 100644
--- a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
@@ -17,10 +17,14 @@
package com.android.settings.biometrics;
import android.content.Context;
+import android.content.Intent;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.preference.Preference;
import com.android.internal.widget.LockPatternUtils;
@@ -29,6 +33,8 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
+import java.lang.ref.WeakReference;
+
public abstract class BiometricStatusPreferenceController extends BasePreferenceController {
protected final UserManager mUm;
@@ -39,6 +45,8 @@
private final BiometricNavigationUtils mBiometricNavigationUtils;
private final ActiveUnlockStatusUtils mActiveUnlockStatusUtils;
+ @NonNull private WeakReference<ActivityResultLauncher<Intent>> mLauncherWeakReference =
+ new WeakReference<>(null);
/**
* @return true if the controller should be shown exclusively.
@@ -118,14 +126,31 @@
preference.setSummary(getSummaryText());
}
+ /**
+ * Set ActivityResultLauncher that will be used later during handlePreferenceTreeClick()
+ *
+ * @param preference the preference being compared
+ * @param launcher the ActivityResultLauncher
+ * @return {@code true} if matched preference.
+ */
+ public boolean setPreferenceTreeClickLauncher(@NonNull Preference preference,
+ @Nullable ActivityResultLauncher<Intent> launcher) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return false;
+ }
+
+ mLauncherWeakReference = new WeakReference<>(launcher);
+ return true;
+ }
+
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
return super.handlePreferenceTreeClick(preference);
}
- return mBiometricNavigationUtils.launchBiometricSettings(
- preference.getContext(), getSettingsClassName(), preference.getExtras());
+ return mBiometricNavigationUtils.launchBiometricSettings(preference.getContext(),
+ getSettingsClassName(), preference.getExtras(), mLauncherWeakReference.get());
}
protected int getUserId() {
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index 7b02b9d..052b8cd 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -33,6 +33,9 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -42,14 +45,19 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
+import com.android.settings.biometrics.BiometricStatusPreferenceController;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.transition.SettingsTransitionHelper;
+import java.util.Collection;
+import java.util.List;
+
/**
* Base fragment with the confirming credential functionality for combined biometrics settings.
*/
@@ -78,6 +86,18 @@
@Nullable private String mRetryPreferenceKey = null;
@Nullable private Bundle mRetryPreferenceExtra = null;
+ private final ActivityResultLauncher<Intent> mFaceOrFingerprintPreferenceLauncher =
+ registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+ this::onFaceOrFingerprintPreferenceResult);
+
+ private void onFaceOrFingerprintPreferenceResult(@Nullable ActivityResult result) {
+ if (result != null && result.getResultCode() == BiometricEnrollBase.RESULT_TIMEOUT) {
+ // When "Face Unlock" or "Fingerprint Unlock" is closed due to entering onStop(),
+ // "Face & Fingerprint Unlock" shall also close itself and back to "Security" page.
+ finish();
+ }
+ }
+
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -165,7 +185,7 @@
extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
extras.putInt(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
- super.onPreferenceTreeClick(preference);
+ onFaceOrFingerprintPreferenceTreeClick(preference);
} catch (IllegalStateException e) {
if (retry) {
mRetryPreferenceKey = preference.getKey();
@@ -200,7 +220,7 @@
final Bundle extras = preference.getExtras();
extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
- super.onPreferenceTreeClick(preference);
+ onFaceOrFingerprintPreferenceTreeClick(preference);
} catch (IllegalStateException e) {
if (retry) {
mRetryPreferenceKey = preference.getKey();
@@ -224,6 +244,33 @@
return BiometricUtils.requestGatekeeperHat(context, gkPwHandle, userId, challenge);
}
+ /**
+ * Handle preference tree click action for "Face Unlock" or "Fingerprint Unlock" with a launcher
+ * because "Face & Fingerprint Unlock" has to close itself when it gets a specific activity
+ * error code.
+ *
+ * @param preference "Face Unlock" or "Fingerprint Unlock" preference.
+ */
+ private void onFaceOrFingerprintPreferenceTreeClick(@NonNull Preference preference) {
+ Collection<List<AbstractPreferenceController>> controllers = getPreferenceControllers();
+ for (List<AbstractPreferenceController> controllerList : controllers) {
+ for (AbstractPreferenceController controller : controllerList) {
+ if (controller instanceof BiometricStatusPreferenceController) {
+ final BiometricStatusPreferenceController biometricController =
+ (BiometricStatusPreferenceController) controller;
+ if (biometricController.setPreferenceTreeClickLauncher(preference,
+ mFaceOrFingerprintPreferenceLauncher)) {
+ if (biometricController.handlePreferenceTreeClick(preference)) {
+ writePreferenceClickMetric(preference);
+ }
+ biometricController.setPreferenceTreeClickLauncher(preference, null);
+ return;
+ }
+ }
+ }
+ }
+ }
+
@Override
public boolean onPreferenceTreeClick(Preference preference) {
return onRetryPreferenceTreeClick(preference, true)
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index cf2c09b..c300bae 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -325,6 +325,8 @@
mFaceManager.revokeChallenge(mSensorId, mUserId, mChallenge);
mToken = null;
}
+ // Let parent "Face & Fingerprint Unlock" can use this error code to close itself.
+ setResult(RESULT_TIMEOUT);
finish();
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 88a05c3..f60cd0c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -669,6 +669,7 @@
public void onStop() {
super.onStop();
if (!getActivity().isChangingConfigurations() && !mLaunchedConfirm && !mIsEnrolling) {
+ setResult(RESULT_TIMEOUT);
getActivity().finish();
}
}
@@ -874,6 +875,12 @@
} else if (requestCode == AUTO_ADD_FIRST_FINGERPRINT_REQUEST) {
if (resultCode != RESULT_FINISHED || data == null) {
Log.d(TAG, "Add first fingerprint, fail or null data, result:" + resultCode);
+ if (resultCode == BiometricEnrollBase.RESULT_TIMEOUT) {
+ // If "Fingerprint Unlock" is closed because of timeout, notify result code
+ // back because "Face & Fingerprint Unlock" has to close itself for timeout
+ // case.
+ setResult(resultCode);
+ }
finish();
return;
}
diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
index 395f88f..90652f0 100644
--- a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,6 +34,7 @@
import android.os.UserManager;
import android.provider.Settings;
+import androidx.activity.result.ActivityResultLauncher;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -55,6 +57,8 @@
@Mock
private UserManager mUserManager;
+ @Mock
+ private ActivityResultLauncher<Intent> mLauncher;
private Context mContext;
private BiometricNavigationUtils mBiometricNavigationUtils;
@@ -72,7 +76,7 @@
when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
- Bundle.EMPTY);
+ Bundle.EMPTY, null);
assertQuietModeDialogLaunchRequested();
}
@@ -82,7 +86,17 @@
when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
- mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isFalse();
+ mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null)).isFalse();
+ }
+
+ @Test
+ public void launchBiometricSettings_quietMode_withLauncher_notThroughLauncher() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+ mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
+ Bundle.EMPTY, mLauncher);
+
+ verify(mLauncher, never()).launch(any(Intent.class));
}
@Test
@@ -90,7 +104,7 @@
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
mBiometricNavigationUtils.launchBiometricSettings(
- mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY);
+ mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null);
assertSettingsPageLaunchRequested(false /* shouldContainExtras */);
}
@@ -100,7 +114,7 @@
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
- mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isTrue();
+ mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null)).isTrue();
}
@Test
@@ -108,17 +122,29 @@
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
final Bundle extras = createNotEmptyExtras();
- mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME, extras);
+ mBiometricNavigationUtils.launchBiometricSettings(
+ mContext, SETTINGS_CLASS_NAME, extras, null);
assertSettingsPageLaunchRequested(true /* shouldContainExtras */);
}
@Test
+ public void launchBiometricSettings_noQuietMode_withLauncher_launchesThroughLauncher() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+ final Bundle extras = createNotEmptyExtras();
+ mBiometricNavigationUtils.launchBiometricSettings(
+ mContext, SETTINGS_CLASS_NAME, extras, mLauncher);
+
+ verify(mLauncher).launch(any(Intent.class));
+ }
+
+ @Test
public void launchBiometricSettings_noQuietMode_withExtras_returnsTrue() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
- mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue();
+ mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras(), null)).isTrue();
}
@Test