diff options
63 files changed, 1250 insertions, 966 deletions
diff --git a/core/java/android/hardware/fingerprint/FingerprintStateListener.java b/core/java/android/hardware/biometrics/BiometricStateListener.java index 551f5120ce2a..2ac0c1edaef0 100644 --- a/core/java/android/hardware/fingerprint/FingerprintStateListener.java +++ b/core/java/android/hardware/biometrics/BiometricStateListener.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.hardware.fingerprint; +package android.hardware.biometrics; import android.annotation.IntDef; @@ -22,10 +22,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Interface for handling state changes in fingerprint-related events. + * Interface for handling state changes in biometric sensors. * @hide */ -public abstract class FingerprintStateListener extends IFingerprintStateListener.Stub { +public abstract class BiometricStateListener extends IBiometricStateListener.Stub { // Operation has not started yet. public static final int STATE_IDLE = 0; @@ -43,16 +43,19 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener @IntDef({STATE_IDLE, STATE_ENROLLING, STATE_KEYGUARD_AUTH, STATE_BP_AUTH, STATE_AUTH_OTHER}) @Retention(RetentionPolicy.SOURCE) - public @interface State {} + public @interface State { + } /** * Defines behavior in response to state update - * @param newState new state of fingerprint sensor + * @param newState new state of the biometric sensor */ - public void onStateChanged(@FingerprintStateListener.State int newState) {} + public void onStateChanged(@BiometricStateListener.State int newState) { + } /** * Invoked when enrollment state changes for the specified user */ - public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {} + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { + } } diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/biometrics/IBiometricStateListener.aidl index 1aa6fa197066..5bdced034017 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl +++ b/core/java/android/hardware/biometrics/IBiometricStateListener.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -13,16 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.hardware.fingerprint; - -import android.hardware.fingerprint.Fingerprint; +package android.hardware.biometrics; /** - * Communication channel for FingerprintManager to register the FingerprintStateListener - * in FingerprintService. + * Communication channel between <Biometric>Manager and <Biometric>Service for passing the + * listener. * @hide */ -oneway interface IFingerprintStateListener { +oneway interface IBiometricStateListener { void onStateChanged(int newState); void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments); } diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 60c4b523094e..28f1f02b7a93 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -45,6 +45,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricPrompt; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.biometrics.BiometricTestSession; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.biometrics.SensorProperties; @@ -918,13 +919,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** - * Forwards FingerprintStateListener to FingerprintService - * @param listener new FingerprintStateListener being added + * Forwards BiometricStateListener to FingerprintService + * @param listener new BiometricStateListener being added * @hide */ - public void registerFingerprintStateListener(@NonNull FingerprintStateListener listener) { + public void registerBiometricStateListener(@NonNull BiometricStateListener listener) { try { - mService.registerFingerprintStateListener(listener); + mService.registerBiometricStateListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index d60bb6ef1543..0b6344617663 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -17,13 +17,13 @@ package android.hardware.fingerprint; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.IBiometricStateListener; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; -import android.hardware.fingerprint.IFingerprintStateListener; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.ISidefpsController; import android.hardware.fingerprint.Fingerprint; @@ -169,6 +169,6 @@ interface IFingerprintService { // Sets the controller for managing the SideFPS overlay. void setSidefpsController(in ISidefpsController controller); - // Registers FingerprintStateListener in list stored by FingerprintService. - void registerFingerprintStateListener(IFingerprintStateListener listener); + // Registers BiometricStateListener. + void registerBiometricStateListener(IBiometricStateListener listener); } diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 390c3b9453c2..f1b110ab29c8 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -172,11 +172,11 @@ public class VcnManager { * * <p>An app that has carrier privileges for any of the subscriptions in the given group may * clear a VCN configuration. This API is ONLY permitted for callers running as the primary - * user. Any active VCN will be torn down. + * user. Any active VCN associated with this configuration will be torn down. * * @param subscriptionGroup the subscription group that the configuration should be applied to - * @throws SecurityException if the caller does not have carrier privileges, or is not running - * as the primary user + * @throws SecurityException if the caller does not have carrier privileges, is not the owner of + * the associated configuration, or is not running as the primary user * @throws IOException if the configuration failed to be cleared from disk. This may occur due * to temporary disk errors, or more permanent conditions such as a full disk. */ @@ -196,8 +196,13 @@ public class VcnManager { /** * Retrieves the list of Subscription Groups for which a VCN Configuration has been set. * - * <p>The returned list will include only subscription groups for which the carrier app is - * privileged, and which have an associated {@link VcnConfig}. + * <p>The returned list will include only subscription groups for which an associated {@link + * VcnConfig} exists, and the app is either: + * + * <ul> + * <li>Carrier privileged for that subscription group, or + * <li>Is the provisioning package of the config + * </ul> * * @throws SecurityException if the caller is not running as the primary user */ diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp index 7d5eb69190b6..d64fe7fb0009 100644 --- a/packages/SettingsLib/Utils/Android.bp +++ b/packages/SettingsLib/Utils/Android.bp @@ -15,6 +15,7 @@ android_library { static_libs: [ "androidx.annotation_annotation", + "modules-utils-build", ], sdk_version: "system_current", diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java index 88e242340dee..fc945040fc83 100644 --- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java +++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java @@ -17,10 +17,11 @@ package com.android.settingslib.utils; import android.os.Build; -import android.os.Build.VERSION; import androidx.annotation.ChecksSdkIntAtLeast; +import com.android.modules.utils.build.SdkLevel; + /** * An util class to check whether the current OS version is higher or equal to sdk version of * device. @@ -34,7 +35,7 @@ public final class BuildCompatUtils { */ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S) public static boolean isAtLeastS() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S; + return SdkLevel.isAtLeastS(); } /** @@ -44,41 +45,17 @@ public final class BuildCompatUtils { */ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S_V2) public static boolean isAtLeastSV2() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2; + return SdkLevel.isAtLeastSv2(); } /** - * Implementation of BuildCompat.isAtLeast*() suitable for use in Settings - * - * <p>This still should try using BuildCompat.isAtLeastR() as source of truth, but also checking - * for VERSION_SDK_INT and VERSION.CODENAME in case when BuildCompat implementation returned - * false. Note that both checks should be >= and not = to make sure that when Android version - * increases (i.e., from R to S), this does not stop working. - * - * <p>Supported configurations: - * - * <ul> - * <li>For current Android release: when new API is not finalized yet (CODENAME = "Tiramisu", - * SDK_INT = 32) - * <li>For current Android release: when new API is finalized (CODENAME = "REL", SDK_INT = 33) - * <li>For next Android release (CODENAME = "U", SDK_INT = 34+) - * </ul> - * - * <p>Note that Build.VERSION_CODES.S cannot be used here until final SDK is available, because - * it is equal to Build.VERSION_CODES.CUR_DEVELOPMENT before API finalization. + * Implementation of BuildCompat.isAtLeastT() suitable for use in Settings * * @return Whether the current OS version is higher or equal to T. */ + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU) public static boolean isAtLeastT() { - if (!isAtLeastS()) { - return false; - } - - return (VERSION.CODENAME.equals("REL") && VERSION.SDK_INT >= 33) - || (VERSION.CODENAME.length() >= 1 - && VERSION.CODENAME.toUpperCase().charAt(0) >= 'T' - && VERSION.CODENAME.toUpperCase().charAt(0) <= 'Z') - || (Build.VERSION.CODENAME.equals("Tiramisu") && Build.VERSION.SDK_INT >= 32); + return SdkLevel.isAtLeastT(); } private BuildCompatUtils() {} diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java index 0f340239cd24..5c9ec4b3e6f1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java @@ -36,7 +36,8 @@ import android.util.Log; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; -import androidx.core.os.BuildCompat; + +import com.android.modules.utils.build.SdkLevel; import java.io.BufferedReader; import java.io.FileReader; @@ -220,7 +221,7 @@ public class DeviceInfoUtils { } private static String getRawPhoneNumber(Context context, int subscriptionId) { - if (BuildCompat.isAtLeastT()) { + if (SdkLevel.isAtLeastT()) { return getRawPhoneNumberFromT(context, subscriptionId); } else { final TelephonyManager telephonyManager = context.getSystemService( diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java index 3a4a8d27b2f3..08aeeaec8bb0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java @@ -31,10 +31,11 @@ import android.util.TypedValue; import android.widget.TextView; import androidx.annotation.RequiresApi; -import androidx.core.os.BuildCompat; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; +import com.android.modules.utils.build.SdkLevel; + /** * Helper class for managing settings preferences that can be disabled * by device admins via user restrictions. @@ -105,7 +106,7 @@ public class RestrictedPreferenceHelper { if (mDisabledSummary) { final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary); if (summaryView != null) { - final CharSequence disabledText = BuildCompat.isAtLeastT() + final CharSequence disabledText = SdkLevel.isAtLeastT() ? getDisabledByAdminUpdatableString() : mContext.getString(R.string.disabled_by_admin_summary_text); if (mDisabledByAdmin) { diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index aaa011458258..a7f12022e172 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -45,12 +45,12 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; -import androidx.core.os.BuildCompat; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.UserIcons; import com.android.launcher3.icons.BaseIconFactory.IconOptions; import com.android.launcher3.icons.IconFactory; +import com.android.modules.utils.build.SdkLevel; import com.android.settingslib.drawable.UserIconDrawable; import com.android.settingslib.fuelgauge.BatteryStatus; @@ -130,7 +130,7 @@ public class Utils { String name = info != null ? info.name : null; if (info.isManagedProfile()) { // We use predefined values for managed profiles - return BuildCompat.isAtLeastT() + return SdkLevel.isAtLeastT() ? getUpdatableManagedUserTitle(context) : context.getString(R.string.managed_user_title); } else if (info.isGuest()) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java index 91d7388bc46d..17ac4307d6a6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java @@ -47,7 +47,8 @@ import android.os.UserHandle; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; -import androidx.core.os.BuildCompat; + +import com.android.modules.utils.build.SdkLevel; /** * Converts the user avatar icon to a circularly clipped one with an optional badge and frame @@ -87,7 +88,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback { * @return drawable containing just the badge */ public static Drawable getManagedUserDrawable(Context context) { - if (BuildCompat.isAtLeastT()) { + if (SdkLevel.isAtLeastT()) { return getUpdatableManagedUserDrawable(context); } else { return getDrawableForDisplayDensity( @@ -226,7 +227,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback { } private static Drawable getManagementBadge(Context context) { - if (BuildCompat.isAtLeastT()) { + if (SdkLevel.isAtLeastT()) { return getUpdatableManagementBadge(context); } else { return getDrawableForDisplayDensity( diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml index c3fc66952395..3c3bc63906f0 100644 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml @@ -22,160 +22,87 @@ android:id="@+id/media_recommendations" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingStart="@dimen/qs_media_padding" - android:paddingEnd="@dimen/qs_media_padding" android:clipChildren="false" android:clipToPadding="false" android:forceHasOverlappingRendering="false" android:background="@drawable/qs_media_background" android:theme="@style/MediaPlayer"> - <androidx.constraintlayout.widget.Guideline - android:id="@+id/media_vertical_start_guideline" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" - app:layout_constraintGuide_percent="0.25" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/media_horizontal_center_guideline" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_percent="0.5" /> + <!-- This view just ensures the full media player is a certain height. --> + <View + android:id="@+id/sizing_view" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_media_session_height_expanded" /> <com.android.internal.widget.CachingIconView android:id="@+id/recommendation_card_icon" - android:layout_width="@dimen/qs_media_icon_size" - android:layout_height="@dimen/qs_media_icon_size" - android:layout_marginTop="@dimen/qs_media_padding" - android:src="@drawable/ic_headset" - style="@style/MediaPlayer.AppIcon" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" - app:layout_constraintHorizontal_bias="0"/> - - <TextView - android:id="@+id/recommendation_card_text" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:maxLines="1" - android:text="@string/controls_media_smartspace_rec_title" - android:fontFamily="google-sans-medium" - android:textDirection="locale" - android:textSize="@dimen/qq_aa_media_rec_header_text_size" - android:hyphenationFrequency="none" - app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" - app:layout_constraintHorizontal_bias="0"/> - - <View - android:id="@+id/recommendation_gradient_view" - android:layout_width="@dimen/qs_aa_media_gradient_bg_width" - android:layout_height="0dp" - android:clipToPadding="false" - android:clipChildren="false" - android:background="@drawable/qs_media_recommendation_bg_gradient" - app:layout_constraintTop_toTopOf="@id/recommendation_card_text" - app:layout_constraintBottom_toBottomOf="@id/recommendation_card_text" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" - app:layout_constraintHorizontal_bias="1"/> + style="@style/MediaPlayer.Recommendation.AppIcon" /> <FrameLayout android:id="@+id/media_cover1_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/media_cover2_container" + android:layout_marginEnd="@dimen/qs_media_rec_album_margin" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintVertical_bias="0.5" + > <ImageView android:id="@+id/media_cover1" android:layout_width="match_parent" android:layout_height="match_parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" android:adjustViewBounds="true" android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" + style="@style/MediaPlayer.Recommendation.Album" android:clipToOutline="true" android:scaleType="centerCrop"/> </FrameLayout> + <!-- TODO(b/223603970): Add title and subtitle below each album cover. --> + <FrameLayout android:id="@+id/media_cover2_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/media_cover1_container" + app:layout_constraintEnd_toStartOf="@id/media_cover3_container" + android:layout_marginEnd="@dimen/qs_media_rec_album_margin" + app:layout_constraintVertical_bias="0.5" + > <ImageView android:id="@+id/media_cover2" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" + style="@style/MediaPlayer.Recommendation.Album" android:clipToOutline="true" android:scaleType="centerCrop"/> </FrameLayout> <FrameLayout android:id="@+id/media_cover3_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/media_cover2_container" + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginEnd="@dimen/qs_media_padding" + app:layout_constraintVertical_bias="0.5" + > <ImageView android:id="@+id/media_cover3" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <FrameLayout - android:id="@+id/media_cover4_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> - <ImageView - android:id="@+id/media_cover4" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <FrameLayout - android:id="@+id/media_cover5_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> - <ImageView - android:id="@+id/media_cover5" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <FrameLayout - android:id="@+id/media_cover6_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - android:background="@drawable/qs_media_light_source"> - <ImageView - android:id="@+id/media_cover6" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Album" + style="@style/MediaPlayer.Recommendation.Album" android:clipToOutline="true" android:scaleType="centerCrop"/> </FrameLayout> @@ -273,4 +200,4 @@ android:text="@string/controls_media_dismiss_button" /> </FrameLayout> -</com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file +</com.android.systemui.util.animation.TransitionLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4725515d16fb..c7d41d3b28d3 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -959,7 +959,6 @@ <dimen name="qs_media_album_radius">14dp</dimen> <dimen name="qs_media_info_margin">12dp</dimen> <dimen name="qs_media_info_spacing">8dp</dimen> - <dimen name="qs_media_icon_size">20dp</dimen> <dimen name="qs_media_icon_offset">4dp</dimen> <dimen name="qs_center_guideline_padding">10dp</dimen> <dimen name="qs_media_action_spacing">4dp</dimen> @@ -980,12 +979,9 @@ <dimen name="qs_media_session_collapsed_guideline">144dp</dimen> <!-- Size of Smartspace media recommendations cards in the QSPanel carousel --> - <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen> - <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen> - <dimen name="qs_aa_media_gradient_bg_width">32dp</dimen> - <dimen name="qs_aa_media_rec_album_margin">8dp</dimen> - <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen> - <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen> + <dimen name="qs_media_rec_album_size">88dp</dimen> + <dimen name="qs_media_rec_album_margin">16dp</dimen> + <dimen name="qs_media_rec_icon_size">24dp</dimen> <!-- Media tap-to-transfer chip for sender device --> <dimen name="media_ttt_chip_outer_padding">16dp</dimen> @@ -1368,7 +1364,7 @@ <dimen name="keyguard_unfold_translation_x">16dp</dimen> - <dimen name="fgs_manager_min_width_minor">100%</dimen> + <dimen name="fgs_manager_list_top_spacing">12dp</dimen> <!-- Dream overlay related dimensions --> <dimen name="dream_overlay_status_bar_height">60dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 0f5115b5c0f5..f7acda7ec379 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2440,14 +2440,16 @@ <!-- Label for the entry point to open the dialog which shows currently running applications [CHAR LIMIT=NONE]--> <plurals name="fgs_manager_footer_label"> - <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> active app</item> - <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> active apps</item> + <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> app is active</item> + <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> apps are active</item> </plurals> <!-- Content description for a dot indicator in the running application indicating that there is new information [CHAR LIMIT=NONE] --> <string name="fgs_dot_content_description">New information</string> <!-- Title for dialog listing applications currently running [CHAR LIMIT=NONE]--> <string name="fgs_manager_dialog_title">Active apps</string> + <!-- Detailed message for dialog listing applications currently running [CHAR LIMIT=NONE]--> + <string name="fgs_manager_dialog_message">Even if you\u2019re not using these apps, they\u2019re still active and might affect battery life</string> <!-- Label of the button to stop an app from running [CHAR LIMIT=12]--> <string name="fgs_manager_app_item_stop_button_label">Stop</string> <!-- Label of the button to stop an app from running but the app is already stopped and the button is disabled [CHAR LIMIT=12]--> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index d7799a7addd1..fc127cc08021 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -653,13 +653,29 @@ <item name="android:textColor">?android:attr/textColorPrimary</item> </style> - <style name="MediaPlayer.AppIcon"> + <style name="MediaPlayer.Recommendation"/> + + <style name="MediaPlayer.Recommendation.AppIcon"> <item name="android:background">@drawable/qs_media_icon_background</item> <item name="android:backgroundTint">@color/media_player_solid_button_bg</item> - <item name="android:padding">4dp</item> + <item name="android:layout_width">@dimen/qs_media_rec_icon_size</item> + <item name="android:layout_height">@dimen/qs_media_rec_icon_size</item> + <item name="layout_constraintTop_toTopOf">parent</item> + <item name="layout_constraintStart_toStartOf">parent</item> + <item name="android:layout_marginTop">@dimen/qs_media_padding</item> + <item name="android:layout_marginStart">@dimen/qs_media_padding</item> + <item name="android:src">@drawable/ic_headset</item> + </style> + + <style name="MediaPlayer.Recommendation.AlbumContainer"> + <item name="android:layout_width">@dimen/qs_media_rec_album_size</item> + <item name="android:layout_height">@dimen/qs_media_rec_album_size</item> + <item name="android:background">@drawable/qs_media_light_source</item> + <item name="android:layout_marginTop">@dimen/qs_media_padding</item> + <item name="android:layout_marginBottom">@dimen/qs_media_padding</item> </style> - <style name="MediaPlayer.Album"> + <style name="MediaPlayer.Recommendation.Album"> <item name="android:backgroundTint">@color/media_player_album_bg</item> </style> @@ -1085,6 +1101,7 @@ <style name="FgsManagerAppLabel" parent="TextAppearance.Dialog.Body"> <item name="android:textDirection">locale</item> + <item name="android:textStyle">bold</item> </style> <style name="FgsManagerAppDuration"> diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml index b6258d1c71eb..c9d76870ebbd 100644 --- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml +++ b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml @@ -15,92 +15,12 @@ ~ limitations under the License --> <ConstraintSet - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:android="http://schemas.android.com/apk/res/android" > <Constraint - android:id="@+id/media_cover1_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline" - app:layout_constraintEnd_toStartOf="@id/media_cover2_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover2_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover1_container" - app:layout_constraintEnd_toStartOf="@id/media_cover3_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover3_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_media_padding" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover2_container" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover4_container" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toBottomOf="@+id/media_cover1_container" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline" - app:layout_constraintEnd_toStartOf="@id/media_cover5_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover5_container" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toBottomOf="@+id/media_cover2_container" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@+id/media_cover4_container" - app:layout_constraintEnd_toStartOf="@+id/media_cover6_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover6_container" - android:layout_width="0dp" - android:layout_height="0dp" - app:layout_constraintTop_toBottomOf="@id/media_cover3_container" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover5_container" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - android:visibility="gone" /> + android:id="@+id/sizing_view" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_media_session_height_collapsed" + /> </ConstraintSet> diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml index 2fb33415e0df..09ffebb8b4a9 100644 --- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml +++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml @@ -15,113 +15,12 @@ ~ limitations under the License --> <ConstraintSet - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:android="http://schemas.android.com/apk/res/android" > <Constraint - android:id="@+id/media_cover1_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline" - app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline" - app:layout_constraintEnd_toStartOf="@id/media_cover2_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="0" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover2_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline" - app:layout_constraintStart_toEndOf="@id/media_cover1_container" - app:layout_constraintEnd_toStartOf="@id/media_cover3_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="0" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover3_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline" - app:layout_constraintStart_toEndOf="@id/media_cover2_container" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="0" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover4_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline" - app:layout_constraintEnd_toStartOf="@id/media_cover5_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover5_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin" - app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@+id/media_cover4_container" - app:layout_constraintEnd_toStartOf="@+id/media_cover6_container" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="1" - android:visibility="gone" /> - - <Constraint - android:id="@+id/media_cover6_container" - android:layout_width="0dp" - android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded" - app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded" - android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert" - android:layout_marginBottom="@dimen/qs_media_padding" - app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover5_container" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="1" - android:visibility="gone" /> + android:id="@+id/sizing_view" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_media_session_height_expanded" + /> </ConstraintSet> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java index bb7a0a719a74..01f417f147d7 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java @@ -568,7 +568,7 @@ public class RotationButtonController { } } - private class TaskStackListenerImpl extends TaskStackChangeListener { + private class TaskStackListenerImpl implements TaskStackChangeListener { // Invalidate any rotation suggestion on task change or activity orientation change // Note: all callbacks happen on main thread diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index c5d54391959a..f65d82a5d6d2 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -26,30 +26,30 @@ import com.android.systemui.shared.recents.model.ThumbnailData; * An interface to track task stack changes. Classes should implement this instead of * {@link android.app.ITaskStackListener} to reduce IPC calls from system services. */ -public abstract class TaskStackChangeListener { +public interface TaskStackChangeListener { // Binder thread callbacks - public void onTaskStackChangedBackground() { } + default void onTaskStackChangedBackground() { } // Main thread callbacks - public void onTaskStackChanged() { } - public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { } - public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { } - public void onActivityUnpinned() { } - public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + default void onTaskStackChanged() { } + default void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { } + default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { } + default void onActivityUnpinned() { } + default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { } - public void onActivityForcedResizable(String packageName, int taskId, int reason) { } - public void onActivityDismissingDockedStack() { } - public void onActivityLaunchOnSecondaryDisplayFailed() { } + default void onActivityForcedResizable(String packageName, int taskId, int reason) { } + default void onActivityDismissingDockedStack() { } + default void onActivityLaunchOnSecondaryDisplayFailed() { } - public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) { + default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) { onActivityLaunchOnSecondaryDisplayFailed(); } /** * @see #onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) */ - public void onActivityLaunchOnSecondaryDisplayRerouted() { } + default void onActivityLaunchOnSecondaryDisplayRerouted() { } /** * Called when an activity was requested to be launched on a secondary display but was rerouted @@ -57,16 +57,16 @@ public abstract class TaskStackChangeListener { * * @param taskInfo info about the Activity's task */ - public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) { + default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) { onActivityLaunchOnSecondaryDisplayRerouted(); } - public void onTaskProfileLocked(int taskId, int userId) { } - public void onTaskCreated(int taskId, ComponentName componentName) { } - public void onTaskRemoved(int taskId) { } - public void onTaskMovedToFront(int taskId) { } + default void onTaskProfileLocked(int taskId, int userId) { } + default void onTaskCreated(int taskId, ComponentName componentName) { } + default void onTaskRemoved(int taskId) { } + default void onTaskMovedToFront(int taskId) { } - public void onTaskMovedToFront(RunningTaskInfo taskInfo) { + default void onTaskMovedToFront(RunningTaskInfo taskInfo) { onTaskMovedToFront(taskInfo.taskId); } @@ -74,13 +74,14 @@ public abstract class TaskStackChangeListener { * Called when a task’s description is changed due to an activity calling * ActivityManagerService.setTaskDescription * - * @param taskInfo info about the task which changed, with {@link TaskInfo#taskDescription} + * @param taskInfo info about the task which changed, with + * {@link RunningTaskInfo#taskDescription} */ - public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { } + default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { } - public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { } + default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { } - public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { } + default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { } /** * Called when a task is reparented to a stack on a different display. @@ -88,22 +89,22 @@ public abstract class TaskStackChangeListener { * @param taskId id of the task which was moved to a different display. * @param newDisplayId id of the new display. */ - public void onTaskDisplayChanged(int taskId, int newDisplayId) { } + default void onTaskDisplayChanged(int taskId, int newDisplayId) { } /** * Called when any additions or deletions to the recent tasks list have been made. */ - public void onRecentTaskListUpdated() { } + default void onRecentTaskListUpdated() { } /** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */ - public void onRecentTaskListFrozenChanged(boolean frozen) { } + default void onRecentTaskListFrozenChanged(boolean frozen) { } /** @see ITaskStackListener#onActivityRotation(int)*/ - public void onActivityRotation(int displayId) { } + default void onActivityRotation(int displayId) { } /** * Called when the lock task mode changes. See ActivityManager#LOCK_TASK_MODE_* and * LockTaskController. */ - public void onLockTaskModeChanged(int mode) { } + default void onLockTaskModeChanged(int mode) { } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt index 5953611b454a..db2b4ac2c669 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt @@ -63,7 +63,8 @@ data class KeyguardFaceListenModel( val primaryUser: Boolean, val scanningAllowedByStrongAuth: Boolean, val secureCameraLaunched: Boolean, - val switchingUser: Boolean + val switchingUser: Boolean, + val udfpsBouncerShowing: Boolean ) : KeyguardListenModel() /** * Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock]. @@ -73,6 +74,7 @@ data class KeyguardActiveUnlockModel( override val userId: Int, override val listening: Boolean, // keep sorted + val awakeKeyguard: Boolean, val authInterruptActive: Boolean, val encryptedOrTimedOut: Boolean, val fpLockout: Boolean, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 3103219d8978..53d7b8cee3be 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -700,6 +700,7 @@ public class KeyguardSecurityContainer extends FrameLayout { } public void reset() { + mViewMode.reset(); mDisappearAnimRunning = false; } @@ -798,9 +799,6 @@ public class KeyguardSecurityContainer extends FrameLayout { mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher); } - Drawable userIcon = findUserIcon(KeyguardUpdateMonitor.getCurrentUser()); - ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon); - updateSecurityViewLocation(); mUserSwitcher = mView.findViewById(R.id.user_switcher_header); @@ -813,6 +811,7 @@ public class KeyguardSecurityContainer extends FrameLayout { mPopup.dismiss(); mPopup = null; } + setupUserSwitcher(); } private Drawable findUserIcon(int userId) { @@ -858,6 +857,12 @@ public class KeyguardSecurityContainer extends FrameLayout { private void setupUserSwitcher() { final UserRecord currentUser = mUserSwitcherController.getCurrentUserRecord(); + if (currentUser == null) { + Log.wtf(TAG, "Current user in user switcher is null."); + return; + } + Drawable userIcon = findUserIcon(currentUser.info.id); + ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon); mUserSwitcher.setText(mUserSwitcherController.getCurrentUserName()); ViewGroup anchor = mView.findViewById(R.id.user_switcher_anchor); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 1a325d3586f4..ce4aad882df9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -219,6 +219,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardSecurityCallback.userActivity(); showMessage(null, null); } + if (mUpdateMonitor.isFaceEnrolled() + && mUpdateMonitor.mRequestActiveUnlockOnUnlockIntent) { + mUpdateMonitor.requestActiveUnlock("unlock-intent, reason=swipeUpOnBouncer", + true); + } } }; private ConfigurationController.ConfigurationListener mConfigurationListener = diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index f1bec819560d..a6feedb50a12 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -56,6 +56,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.SensorPrivacyManager; +import android.hardware.biometrics.BiometricFaceConstants; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; @@ -88,6 +89,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -246,6 +248,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + public final boolean mRequestActiveUnlockOnAssistant; + public final boolean mRequestActiveUnlockOnWakeup; + public final boolean mInitiateActiveUnlockOnWakeup; + public final boolean mRequestActiveUnlockOnUnlockIntent; + public final boolean mRequestActiveUnlockOnBioFail; + private final Context mContext; private final boolean mIsPrimaryUser; private final boolean mIsAutomotive; @@ -281,6 +289,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mGoingToSleep; private boolean mBouncerFullyShown; private boolean mBouncerIsOrWillBeShowing; + private boolean mUdfpsBouncerShowing; private boolean mAuthInterruptActive; private boolean mNeedsSlowUnlockTransition; private boolean mAssistantVisible; @@ -451,10 +460,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - if (KeyguardUpdateMonitor.getCurrentUser() == userId && getUserHasTrust(userId)) { + if (KeyguardUpdateMonitor.getCurrentUser() == userId) { CharSequence message = null; - if (trustGrantedMessages != null && trustGrantedMessages.size() > 0) { - message = trustGrantedMessages.get(0); // for now only shows the first in the list + final boolean userHasTrust = getUserHasTrust(userId); + if (userHasTrust && trustGrantedMessages != null) { + for (String msg : trustGrantedMessages) { + if (!TextUtils.isEmpty(msg)) { + message = msg; + break; + } + } } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -463,6 +478,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } } + } @Override @@ -1354,8 +1370,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab void setAssistantVisible(boolean assistantVisible) { mAssistantVisible = assistantVisible; updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE); - if (mAssistantVisible) { - requestActiveUnlock(); + if (mAssistantVisible && mRequestActiveUnlockOnAssistant) { + requestActiveUnlock("assistant", false); } } @@ -1502,11 +1518,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onAuthenticationFailed() { + if (mRequestActiveUnlockOnBioFail) { + requestActiveUnlock("biometric-failure, extra=fingerprintFailure", + true); + } handleFingerprintAuthFailed(); - - // TODO(b/225231929): Refactor as needed, add tests, etc. - mTrustManager.reportUserRequestedUnlock( - KeyguardUpdateMonitor.getCurrentUser(), true); } @Override @@ -1564,6 +1580,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onAuthenticationFailed() { + if (shouldRequestActiveUnlockOnFaceError()) { + String reason = + mKeyguardBypassController.canBypass() ? "bypass" + : mUdfpsBouncerShowing ? "udfpsBouncer" : + mBouncerFullyShown ? "bouncer" : "udfpsFpDown"; + requestActiveUnlock("biometric-failure" + + ", extra=faceFailure-" + reason, true); + } + handleFaceAuthFailed(); if (mKeyguardBypassController != null) { mKeyguardBypassController.setUserHasDeviceEntryIntent(false); @@ -1592,12 +1617,23 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (mKeyguardBypassController != null) { mKeyguardBypassController.setUserHasDeviceEntryIntent(false); } + if (errMsgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT + && shouldRequestActiveUnlockOnFaceError()) { + requestActiveUnlock("biometric-failure" + + ", extra=faceError-" + errMsgId, true); + } } @Override public void onAuthenticationAcquired(int acquireInfo) { handleFaceAcquired(acquireInfo); } + + private boolean shouldRequestActiveUnlockOnFaceError() { + return mRequestActiveUnlockOnBioFail + && (mKeyguardBypassController.canBypass() || mBouncerFullyShown + || mUdfpsBouncerShowing || mAuthController.isUdfpsFingerDown()); + } }; @VisibleForTesting @@ -1713,7 +1749,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp"); Assert.isMainThread(); updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE); - requestActiveUnlock(); + if (mRequestActiveUnlockOnWakeup) { + requestActiveUnlock("wake-unlock"); + } else if (mInitiateActiveUnlockOnWakeup) { + initiateActiveUnlock("wake-initiate"); + } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1860,6 +1900,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab dumpManager.registerDumpable(getClass().getName(), this); mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class); + // TODO, b/222459888: add official configurable names to Settings.java + mRequestActiveUnlockOnWakeup = Settings.Global.getInt( + mContext.getContentResolver(), "wake-unlock", 0) == 1; + mInitiateActiveUnlockOnWakeup = Settings.Global.getInt( + mContext.getContentResolver(), "wake-initiate", 1) == 1; + mRequestActiveUnlockOnUnlockIntent = Settings.Global.getInt( + mContext.getContentResolver(), "unlock-intent", 0) == 1; + mRequestActiveUnlockOnBioFail = Settings.Global.getInt( + mContext.getContentResolver(), "bio-fail", 0) == 1; + mRequestActiveUnlockOnAssistant = Settings.Global.getInt( + mContext.getContentResolver(), "assistant", 0) == 1; + mHandler = new Handler(mainLooper) { @Override public void handleMessage(Message msg) { @@ -2194,7 +2246,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } // don't start running fingerprint until they're registered - if (!mAuthController.areAllAuthenticatorsRegistered()) { + if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) { return; } final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported()); @@ -2240,7 +2292,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } mAuthInterruptActive = active; updateFaceListeningState(BIOMETRIC_ACTION_UPDATE); - requestActiveUnlock(); + if (mRequestActiveUnlockOnWakeup) { + requestActiveUnlock("wake-unlock, extra=onReach"); + } else if (mInitiateActiveUnlockOnWakeup) { + initiateActiveUnlock("wake-initiate, extra=onReach"); + } } /** @@ -2290,25 +2346,69 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * Attempts to trigger active unlock. + * Initiates active unlock to get the unlock token ready. */ - public void requestActiveUnlock() { + public void initiateActiveUnlock(String reason) { // If this message exists, FP has already authenticated, so wait until that is handled if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) { return; } if (shouldTriggerActiveUnlock()) { - // TODO(b/225231929): Refactor surrounding code to reflect calling of new method + if (DEBUG) { + Log.d("ActiveUnlock", "initiate active unlock triggerReason=" + reason); + } mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser()); } } + /** + * Attempts to trigger active unlock from trust agent. + */ + public void requestActiveUnlock(String reason, boolean dismissKeyguard) { + // If this message exists, FP has already authenticated, so wait until that is handled + if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) { + return; + } + + if (shouldTriggerActiveUnlock()) { + if (DEBUG) { + Log.d("ActiveUnlock", "reportUserRequestedUnlock triggerReason=" + reason + + " dismissKeyguard=" + dismissKeyguard); + } + mTrustManager.reportUserRequestedUnlock(KeyguardUpdateMonitor.getCurrentUser(), + dismissKeyguard); + } + } + + /** + * Attempts to trigger active unlock from trust agent. + * Only dismisses the keyguard if only face is enrolled (no FP) and bypass is enabled. + */ + public void requestActiveUnlock(String reason) { + requestActiveUnlock(reason, isFaceEnrolled() && !isUdfpsEnrolled() + && mKeyguardBypassController.getBypassEnabled()); + } + + /** + * Whether the UDFPS bouncer is showing. + */ + public void setUdfpsBouncerShowing(boolean showing) { + mUdfpsBouncerShowing = showing; + if (mUdfpsBouncerShowing) { + updateFaceListeningState(BIOMETRIC_ACTION_START); + if (mRequestActiveUnlockOnUnlockIntent) { + requestActiveUnlock("unlock-intent, extra=udfpsBouncer", true); + } + } + } + private boolean shouldTriggerActiveUnlock() { // Triggers: final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant(); - final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep - && mStatusBarState != StatusBarState.SHADE_LOCKED; + final boolean awakeKeyguard = mBouncerFullyShown || mUdfpsBouncerShowing + || (mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep + && mStatusBarState != StatusBarState.SHADE_LOCKED); // Gates: final int user = getCurrentUser(); @@ -2341,20 +2441,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab && !mSecureCameraLaunched; // Aggregate relevant fields for debug logging. - if (DEBUG_ACTIVE_UNLOCK || DEBUG_SPEW) { - maybeLogListenerModelData( - new KeyguardActiveUnlockModel( - System.currentTimeMillis(), - user, - shouldTriggerActiveUnlock, - mAuthInterruptActive, - isEncryptedOrTimedOut, - fpLockedout, - isLockDown, - mSwitchingUser, - triggerActiveUnlockForAssistant, - userCanDismissLockScreen)); - } + maybeLogListenerModelData( + new KeyguardActiveUnlockModel( + System.currentTimeMillis(), + user, + shouldTriggerActiveUnlock, + awakeKeyguard, + mAuthInterruptActive, + isEncryptedOrTimedOut, + fpLockedout, + isLockDown, + mSwitchingUser, + triggerActiveUnlockForAssistant, + userCanDismissLockScreen)); return shouldTriggerActiveUnlock; } @@ -2507,7 +2606,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || mOccludingAppRequestingFace || awakeKeyguard || shouldListenForFaceAssistant - || mAuthController.isUdfpsFingerDown()) + || mAuthController.isUdfpsFingerDown() + || mUdfpsBouncerShowing) && !mSwitchingUser && !faceDisabledForUser && becauseCannotSkipBouncer && !mKeyguardGoingAway && biometricEnabledForUser && !mLockIconPressed && strongAuthAllowsScanning && mIsPrimaryUser @@ -2537,7 +2637,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mIsPrimaryUser, strongAuthAllowsScanning, mSecureCameraLaunched, - mSwitchingUser)); + mSwitchingUser, + mUdfpsBouncerShowing)); } return shouldListen; @@ -2550,8 +2651,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } if (DEBUG_ACTIVE_UNLOCK - && model instanceof KeyguardActiveUnlockModel - && model.getListening()) { + && model instanceof KeyguardActiveUnlockModel) { mListenModels.add(model); return; } @@ -3133,6 +3233,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } if (wasBouncerFullyShown != mBouncerFullyShown) { + if (mBouncerFullyShown && mRequestActiveUnlockOnUnlockIntent) { + requestActiveUnlock("unlock-intent, reason=bouncerFullyShown", true); + } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -3619,8 +3722,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId); BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId); pw.println(" Fingerprint state (user=" + userId + ")"); - pw.println(" areAllAuthenticatorsRegistered=" - + mAuthController.areAllAuthenticatorsRegistered()); + pw.println(" areAllFpAuthenticatorsRegistered=" + + mAuthController.areAllFingerprintAuthenticatorsRegistered()); pw.println(" allowed=" + (fingerprint != null && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric))); @@ -3641,6 +3744,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true)); pw.println(" mBouncerIsOrWillBeShowing=" + mBouncerIsOrWillBeShowing); pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState)); + pw.println(" mUdfpsBouncerShowing=" + mUdfpsBouncerShowing); } } if (mFaceManager != null && mFaceManager.isHardwareDetected()) { @@ -3667,6 +3771,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } mListenModels.print(pw); + pw.println("Enabled active unlock triggers:"); + pw.println(" mRequestActiveUnlockOnWakeup=" + mRequestActiveUnlockOnWakeup); + pw.println(" mInitiateActiveUnlockOnWakeup=" + mInitiateActiveUnlockOnWakeup); + pw.println(" mRequestActiveUnlockOnUnlockIntent=" + mRequestActiveUnlockOnUnlockIntent); + pw.println(" mRequestActiveUnlockOnBiometricFail=" + mRequestActiveUnlockOnBioFail); + pw.println(" mRequestActiveUnlockOnAssistant=" + mRequestActiveUnlockOnAssistant); + if (mIsAutomotive) { pw.println(" Running on Automotive build"); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index b05bc245a79f..15d0648ae163 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -37,6 +37,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode; import android.hardware.biometrics.BiometricPrompt; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; @@ -45,7 +46,6 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; -import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; @@ -138,7 +138,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser; @NonNull private final SensorPrivacyManager mSensorPrivacyManager; private final WakefulnessLifecycle mWakefulnessLifecycle; - private boolean mAllAuthenticatorsRegistered; + private boolean mAllFingerprintAuthenticatorsRegistered; @NonNull private final UserManager mUserManager; @NonNull private final LockPatternUtils mLockPatternUtils; private final @Background DelayableExecutor mBackgroundExecutor; @@ -157,12 +157,12 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba @Override public void onAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { - mHandler.post(() -> handleAllAuthenticatorsRegistered(sensors)); + mHandler.post(() -> handleAllFingerprintAuthenticatorsRegistered(sensors)); } }; - private final FingerprintStateListener mFingerprintStateListener = - new FingerprintStateListener() { + private final BiometricStateListener mBiometricStateListener = + new BiometricStateListener() { @Override public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { mHandler.post( @@ -234,20 +234,20 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } /** - * Whether all authentictors have been registered. + * Whether all fingerprint authentictors have been registered. */ - public boolean areAllAuthenticatorsRegistered() { - return mAllAuthenticatorsRegistered; + public boolean areAllFingerprintAuthenticatorsRegistered() { + return mAllFingerprintAuthenticatorsRegistered; } - private void handleAllAuthenticatorsRegistered( + private void handleAllFingerprintAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { mExecution.assertIsMainThread(); if (DEBUG) { Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString( sensors.toArray())); } - mAllAuthenticatorsRegistered = true; + mAllFingerprintAuthenticatorsRegistered = true; mFpProps = sensors; List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>(); @@ -281,7 +281,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } - mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); + mFingerprintManager.registerBiometricStateListener(mBiometricStateListener); } private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 2ac240885faa..eba87e49d35b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -799,6 +799,11 @@ public class UdfpsController implements DozeReceiver { if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) { mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false); } + + if (mKeyguardUpdateMonitor.mRequestActiveUnlockOnUnlockIntent) { + mKeyguardUpdateMonitor.requestActiveUnlock("unlock-intent extra=udfpsFingerDown", + true); + } } mOnFingerDown = true; mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major); diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java index aaa4d9eefd29..c4531b573d22 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java @@ -42,10 +42,14 @@ import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.commandline.Command; +import com.android.systemui.statusbar.commandline.CommandRegistry; import com.android.systemui.util.settings.SecureSettings; import java.io.PrintWriter; +import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.TreeMap; @@ -59,6 +63,10 @@ import javax.inject.Named; * * Flags can be set (or unset) via the following adb command: * + * adb shell cmd statusbar flag <id> <on|off|toggle|erase> + * + * Alternatively, you can change flags via a broadcast intent: + * * adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>] * * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command. @@ -67,6 +75,7 @@ import javax.inject.Named; public class FeatureFlagsDebug implements FeatureFlags, Dumpable { private static final String TAG = "SysUIFlags"; static final String ALL_FLAGS = "all_flags"; + private static final String FLAG_COMMAND = "flag"; private final FlagManager mFlagManager; private final SecureSettings mSecureSettings; @@ -86,12 +95,15 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { @Main Resources resources, DumpManager dumpManager, @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, + CommandRegistry commandRegistry, IStatusBarService barService) { mFlagManager = flagManager; mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; mAllFlags = allFlags; + mBarService = barService; + IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); @@ -100,7 +112,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { context.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); dumpManager.registerDumpable(TAG, this); - mBarService = barService; + commandRegistry.registerCommand(FLAG_COMMAND, FlagCommand::new); } @Override @@ -276,6 +288,31 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { } } + private void setBooleanFlagInternal(Flag<?> flag, boolean value) { + if (flag instanceof BooleanFlag) { + setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); + } else if (flag instanceof ResourceBooleanFlag) { + setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); + } else if (flag instanceof SysPropBooleanFlag) { + // Store SysProp flags in SystemProperties where they can read by outside parties. + mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value); + dispatchListenersAndMaybeRestart(flag.getId(), + FeatureFlagsDebug.this::restartAndroid); + } else { + throw new IllegalArgumentException("Unknown flag type"); + } + } + + private void setStringFlagInternal(Flag<?> flag, String value) { + if (flag instanceof StringFlag) { + setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE); + } else if (flag instanceof ResourceStringFlag) { + setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE); + } else { + throw new IllegalArgumentException("Unknown flag type"); + } + } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -327,24 +364,19 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { } Object value = extras.get(EXTRA_VALUE); - if (flag instanceof BooleanFlag && value instanceof Boolean) { - setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); - } else if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) { - setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); - } else if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) { - // Store SysProp flags in SystemProperties where they can read by outside parties. - mSystemProperties.setBoolean( - ((SysPropBooleanFlag) flag).getName(), (Boolean) value); - dispatchListenersAndMaybeRestart(flag.getId(), - FeatureFlagsDebug.this::restartAndroid); - } else if (flag instanceof StringFlag && value instanceof String) { - setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE); - } else if (flag instanceof ResourceStringFlag && value instanceof String) { - setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE); - } else { + + try { + if (value instanceof Boolean) { + setBooleanFlagInternal(flag, (Boolean) value); + } else if (value instanceof String) { + setStringFlagInternal(flag, (String) value); + } else { + throw new IllegalArgumentException("Unknown value type"); + } + } catch (IllegalArgumentException e) { Log.w(TAG, - "Unable to set " + id + " of type " + flag.getClass() + " to value of type " - + (value == null ? null : value.getClass())); + "Unable to set " + flag.getId() + " of type " + flag.getClass() + + " to value of type " + (value == null ? null : value.getClass())); } } @@ -388,4 +420,153 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { mStringFlagCache.forEach((key, value) -> pw.println(" sysui_flag_" + key + ": [length=" + value.length() + "] \"" + value + "\"")); } + + class FlagCommand implements Command { + private final List<String> mOnCommands = List.of("true", "on", "1", "enabled"); + private final List<String> mOffCommands = List.of("false", "off", "0", "disable"); + + @Override + public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) { + if (args.size() == 0) { + pw.println("Error: no flag id supplied"); + help(pw); + pw.println(); + printKnownFlags(pw); + return; + } + + if (args.size() > 2) { + pw.println("Invalid number of arguments."); + help(pw); + return; + } + + int id = 0; + try { + id = Integer.parseInt(args.get(0)); + if (!mAllFlags.containsKey(id)) { + pw.println("Unknown flag id: " + id); + pw.println(); + printKnownFlags(pw); + return; + } + } catch (NumberFormatException e) { + id = flagNameToId(args.get(0)); + if (id == 0) { + pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0)); + return; + } + } + Flag<?> flag = mAllFlags.get(id); + + String cmd = ""; + if (args.size() == 2) { + cmd = args.get(1).toLowerCase(); + } + + if ("erase".equals(cmd) || "reset".equals(cmd)) { + eraseFlag(flag); + return; + } + + boolean newValue = true; + if (args.size() == 1 || "toggle".equals(cmd)) { + boolean enabled = isBooleanFlagEnabled(flag); + + if (args.size() == 1) { + pw.println("Flag " + id + " is " + enabled); + return; + } + + newValue = !enabled; + } else { + newValue = mOnCommands.contains(cmd); + if (!newValue && !mOffCommands.contains(cmd)) { + pw.println("Invalid on/off argument supplied"); + help(pw); + return; + } + } + + pw.flush(); // Next command will restart sysui, so flush before we do so. + setBooleanFlagInternal(flag, newValue); + } + + @Override + public void help(PrintWriter pw) { + pw.println( + "Usage: adb shell cmd statusbar flag <id> " + + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]"); + pw.println("The id can either be a numeric integer or the corresponding field name"); + pw.println( + "If no argument is supplied after the id, the flags runtime value is output"); + } + + private boolean isBooleanFlagEnabled(Flag<?> flag) { + if (flag instanceof BooleanFlag) { + return isEnabled((BooleanFlag) flag); + } else if (flag instanceof ResourceBooleanFlag) { + return isEnabled((ResourceBooleanFlag) flag); + } else if (flag instanceof SysPropFlag) { + return isEnabled((SysPropBooleanFlag) flag); + } + + return false; + } + + private int flagNameToId(String flagName) { + List<Field> fields = Flags.getFlagFields(); + for (Field field : fields) { + if (flagName.equals(field.getName())) { + return fieldToId(field); + } + } + + return 0; + } + + private int fieldToId(Field field) { + try { + Flag<?> flag = (Flag<?>) field.get(null); + return flag.getId(); + } catch (IllegalAccessException e) { + // no-op + } + + return 0; + } + + private void printKnownFlags(PrintWriter pw) { + List<Field> fields = Flags.getFlagFields(); + + int longestFieldName = 0; + for (Field field : fields) { + longestFieldName = Math.max(longestFieldName, field.getName().length()); + } + + pw.println("Known Flags:"); + pw.print("Flag Name"); + for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) { + pw.print(" "); + } + pw.println("ID Enabled?"); + for (int i = 0; i < longestFieldName; i++) { + pw.print("="); + } + pw.println(" ==== ========"); + for (Field field : fields) { + int id = fieldToId(field); + if (id == 0 || !mAllFlags.containsKey(id)) { + continue; + } + pw.print(field.getName()); + int fieldWidth = field.getName().length(); + for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) { + pw.print(" "); + } + pw.printf("%-4d ", id); + pw.println(isBooleanFlagEnabled(mAllFlags.get(id))); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 44580aa4230a..afa7d5e0a9c4 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -20,7 +20,9 @@ import com.android.internal.annotations.Keep; import com.android.systemui.R; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -182,25 +184,36 @@ public class Flags { if (sFlagMap != null) { return sFlagMap; } + Map<Integer, Flag<?>> flags = new HashMap<>(); + List<Field> flagFields = getFlagFields(); + + for (Field field : flagFields) { + try { + Flag<?> flag = (Flag<?>) field.get(null); + flags.put(flag.getId(), flag); + } catch (IllegalAccessException e) { + // no-op + } + } + sFlagMap = flags; + + return sFlagMap; + } + + static List<Field> getFlagFields() { Field[] fields = Flags.class.getFields(); + List<Field> result = new ArrayList<>(); for (Field field : fields) { Class<?> t = field.getType(); if (Flag.class.isAssignableFrom(t)) { - try { - Flag<?> flag = (Flag<?>) field.get(null); - flags.put(flag.getId(), flag); - } catch (IllegalAccessException e) { - // no-op - } + result.add(field); } } - sFlagMap = flags; - - return sFlagMap; + return result; } // | . . . . . . . . . . . . . . . . . . . | // | | diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index a264afd3e0ef..d3e2fc8f2424 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -100,8 +100,7 @@ public class MediaControlPanel { + ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity"; private static final String EXTRAS_SMARTSPACE_INTENT = "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT"; - private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3; - private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6; + private static final int MEDIA_RECOMMENDATION_MAX_NUM = 3; private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name"; private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND"; private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME"; @@ -1001,11 +1000,6 @@ public class MediaControlPanel { appName = packageManager.getApplicationLabel(applicationInfo); } } - // Set the app name as card's title. - if (!TextUtils.isEmpty(appName)) { - TextView headerTitleText = mRecommendationViewHolder.getCardText(); - headerTitleText.setText(appName); - } // Set up media rec card's tap action if applicable. setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(), @@ -1016,11 +1010,6 @@ public class MediaControlPanel { List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems(); List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers(); - List<Integer> mediaCoverItemsResIds = mRecommendationViewHolder.getMediaCoverItemsResIds(); - List<Integer> mediaCoverContainersResIds = - mRecommendationViewHolder.getMediaCoverContainersResIds(); - ConstraintSet expandedSet = mMediaViewController.getExpandedLayout(); - ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), MEDIA_RECOMMENDATION_MAX_NUM); int uiComponentIndex = 0; @@ -1065,21 +1054,6 @@ public class MediaControlPanel { recommendation.getTitle(), artistName, appName)); } - if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) { - setVisibleAndAlpha(collapsedSet, - mediaCoverItemsResIds.get(uiComponentIndex), true); - setVisibleAndAlpha(collapsedSet, - mediaCoverContainersResIds.get(uiComponentIndex), true); - } else { - setVisibleAndAlpha(collapsedSet, - mediaCoverItemsResIds.get(uiComponentIndex), false); - setVisibleAndAlpha(collapsedSet, - mediaCoverContainersResIds.get(uiComponentIndex), false); - } - setVisibleAndAlpha(expandedSet, - mediaCoverItemsResIds.get(uiComponentIndex), true); - setVisibleAndAlpha(expandedSet, - mediaCoverContainersResIds.get(uiComponentIndex), true); uiComponentIndex++; } diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt index c0f79d575dc6..b2acc92fb30d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt @@ -31,35 +31,14 @@ class RecommendationViewHolder private constructor(itemView: View) { // Recommendation screen val cardIcon = itemView.requireViewById<ImageView>(R.id.recommendation_card_icon) - val cardText = itemView.requireViewById<TextView>(R.id.recommendation_card_text) val mediaCoverItems = listOf<ImageView>( itemView.requireViewById(R.id.media_cover1), itemView.requireViewById(R.id.media_cover2), - itemView.requireViewById(R.id.media_cover3), - itemView.requireViewById(R.id.media_cover4), - itemView.requireViewById(R.id.media_cover5), - itemView.requireViewById(R.id.media_cover6)) + itemView.requireViewById(R.id.media_cover3)) val mediaCoverContainers = listOf<ViewGroup>( itemView.requireViewById(R.id.media_cover1_container), itemView.requireViewById(R.id.media_cover2_container), - itemView.requireViewById(R.id.media_cover3_container), - itemView.requireViewById(R.id.media_cover4_container), - itemView.requireViewById(R.id.media_cover5_container), - itemView.requireViewById(R.id.media_cover6_container)) - val mediaCoverItemsResIds = listOf<Int>( - R.id.media_cover1, - R.id.media_cover2, - R.id.media_cover3, - R.id.media_cover4, - R.id.media_cover5, - R.id.media_cover6) - val mediaCoverContainersResIds = listOf<Int>( - R.id.media_cover1_container, - R.id.media_cover2_container, - R.id.media_cover3_container, - R.id.media_cover4_container, - R.id.media_cover5_container, - R.id.media_cover6_container) + itemView.requireViewById(R.id.media_cover3_container)) // Settings/Guts screen val longPressText = itemView.requireViewById<TextView>(R.id.remove_text) @@ -107,19 +86,12 @@ class RecommendationViewHolder private constructor(itemView: View) { // Res Ids for the control components on the recommendation view. val controlsIds = setOf( R.id.recommendation_card_icon, - R.id.recommendation_card_text, R.id.media_cover1, R.id.media_cover2, R.id.media_cover3, - R.id.media_cover4, - R.id.media_cover5, - R.id.media_cover6, R.id.media_cover1_container, R.id.media_cover2_container, R.id.media_cover3_container, - R.id.media_cover4_container, - R.id.media_cover5_container, - R.id.media_cover6_container ) // Res Ids for the components on the guts panel. diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index cc37ef40321c..13340b7245fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -234,6 +234,7 @@ class FgsManagerController @Inject constructor( val dialog = SystemUIDialog(context) dialog.setTitle(R.string.fgs_manager_dialog_title) + dialog.setMessage(R.string.fgs_manager_dialog_message) val dialogContext = dialog.context @@ -241,7 +242,9 @@ class FgsManagerController @Inject constructor( recyclerView.layoutManager = LinearLayoutManager(dialogContext) recyclerView.adapter = appListAdapter - dialog.setView(recyclerView) + val topSpacing = dialogContext.resources + .getDimensionPixelSize(R.dimen.fgs_manager_list_top_spacing) + dialog.setView(recyclerView, 0, topSpacing, 0, 0) this.dialog = dialog diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 83138f0666c1..551e8b51ae11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -502,8 +502,8 @@ public class KeyguardIndicationController { private void updateLockScreenTrustMsg(int userId, CharSequence trustGrantedIndication, CharSequence trustManagedIndication) { - if (!TextUtils.isEmpty(trustGrantedIndication) - && mKeyguardUpdateMonitor.getUserHasTrust(userId)) { + final boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(userId); + if (!TextUtils.isEmpty(trustGrantedIndication) && userHasTrust) { mRotateTextViewController.updateIndication( INDICATION_TYPE_TRUST, new KeyguardIndication.Builder() @@ -513,7 +513,7 @@ public class KeyguardIndicationController { false); } else if (!TextUtils.isEmpty(trustManagedIndication) && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId) - && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) { + && !userHasTrust) { mRotateTextViewController.updateIndication( INDICATION_TYPE_TRUST, new KeyguardIndication.Builder() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index 7db677ab6305..3e32b64ebe3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -71,7 +71,13 @@ class KeyguardLiftController @Inject constructor( isListening = false updateListeningState() keyguardUpdateMonitor.requestFaceAuth(true) - keyguardUpdateMonitor.requestActiveUnlock() + if (keyguardUpdateMonitor.mRequestActiveUnlockOnWakeup) { + keyguardUpdateMonitor.requestActiveUnlock("wake-unlock," + + " extra=KeyguardLiftController") + } else if (keyguardUpdateMonitor.mInitiateActiveUnlockOnWakeup) { + keyguardUpdateMonitor.initiateActiveUnlock("wake-initiate," + + " extra=KeyguardLiftController") + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index c1142edec77c..f269c8d9b13e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -3336,6 +3336,12 @@ public class NotificationPanelViewController extends PanelViewController { .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT); startUnlockHintAnimation(); } + if (mUpdateMonitor.isFaceEnrolled() + && mUpdateMonitor.mRequestActiveUnlockOnUnlockIntent + && mKeyguardBypassController.canBypass()) { + mUpdateMonitor.requestActiveUnlock("unlock-intent," + + " extra=lockScreenEmptySpaceTap", true); + } } return true; case StatusBarState.SHADE_LOCKED: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index 56c74bf98e6b..24660b261c51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -288,7 +288,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW final boolean keyguardOrAod = state.mKeyguardShowing || (state.mDozing && mDozeParameters.getAlwaysOn()); if ((keyguardOrAod && !state.mBackdropShowing && !state.mLightRevealScrimOpaque) - || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) { + || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()) { // Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a // solid backdrop. Also, show it if we are currently animating between the // keyguard and the surface behind the keyguard - we want to use the wallpaper as a diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 49cd56f0176d..8016ea598b03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -589,10 +589,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } private void updateAlternateAuthShowing(boolean updateScrim) { + final boolean isShowingAltAuth = isShowingAlternateAuth(); if (mKeyguardMessageAreaController != null) { - mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAlternateAuth()); + mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAltAuth); } - mBypassController.setAltBouncerShowing(isShowingAlternateAuth()); + mBypassController.setAltBouncerShowing(isShowingAltAuth); + mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth); if (updateScrim) { mCentralSurfaces.updateScrimController(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt index cc606de1b0b9..b1e2012ecd40 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt @@ -97,5 +97,6 @@ private fun faceModel(user: Int) = KeyguardFaceListenModel( primaryUser = false, scanningAllowedByStrongAuth = false, secureCameraLaunched = false, - switchingUser = false + switchingUser = false, + udfpsBouncerShowing = false ) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 14c903c86b62..ba058c71a7f4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -291,7 +291,9 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Test public void testTwoOrMoreUsersDoesAllowDropDown() { // GIVEN one user has been setup - when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(2)); + ArrayList<UserRecord> records = buildUserRecords(2); + when(mUserSwitcherController.getCurrentUserRecord()).thenReturn(records.get(0)); + when(mUserSwitcherController.getUsers()).thenReturn(records); // WHEN UserSwitcherViewMode is initialized setupUserSwitcher(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 775addd9390b..86a4f5ad43b0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -269,7 +269,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.registerCallback(mTestCallback); mTestableLooper.processAllMessages(); - when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(true); + when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(true); } @After @@ -499,7 +499,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void test_doesNotTryToAuthenticateFingerprint_whenAuthenticatorsNotRegistered() { - when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(false); + when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(false); mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 4858ab5234f8..28da2f13eb69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -50,6 +50,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.IBiometricSysuiReceiver; @@ -60,7 +61,6 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; -import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.Handler; @@ -151,7 +151,7 @@ public class AuthControllerTest extends SysuiTestCase { @Captor ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor; @Captor - ArgumentCaptor<FingerprintStateListener> mFingerprintStateCaptor; + ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor; @Captor ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor; @@ -226,7 +226,7 @@ public class AuthControllerTest extends SysuiTestCase { // Callback tests @Test - public void testRegistersFingerprintStateListener_afterAllAuthenticatorsAreRegistered() + public void testRegistersBiometricStateListener_afterAllAuthenticatorsAreRegistered() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); @@ -242,12 +242,12 @@ public class AuthControllerTest extends SysuiTestCase { mAuthenticatorsRegisteredCaptor.capture()); mTestableLooper.processAllMessages(); - verify(mFingerprintManager, never()).registerFingerprintStateListener(any()); + verify(mFingerprintManager, never()).registerBiometricStateListener(any()); mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); - verify(mFingerprintManager).registerFingerprintStateListener(any()); + verify(mFingerprintManager).registerBiometricStateListener(any()); } @Test @@ -269,11 +269,11 @@ public class AuthControllerTest extends SysuiTestCase { mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); - verify(mFingerprintManager).registerFingerprintStateListener( - mFingerprintStateCaptor.capture()); + verify(mFingerprintManager).registerBiometricStateListener( + mBiometricStateCaptor.capture()); // Enrollments changed for an unknown sensor. - mFingerprintStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */, + mBiometricStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */, 0xbeef /* sensorId */, true /* hasEnrollments */); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt index 6626bbe69706..b43856aae4cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt @@ -24,7 +24,11 @@ import android.test.suitebuilder.annotation.SmallTest import com.android.internal.statusbar.IStatusBarService import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.commandline.Command +import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.withArgCaptor @@ -37,10 +41,12 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.anyString +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.inOrder import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.verifyZeroInteractions import org.mockito.MockitoAnnotations import java.io.PrintWriter import java.io.Serializable @@ -56,16 +62,18 @@ import org.mockito.Mockito.`when` as whenever class FeatureFlagsDebugTest : SysuiTestCase() { private lateinit var mFeatureFlagsDebug: FeatureFlagsDebug - @Mock private lateinit var mFlagManager: FlagManager - @Mock private lateinit var mMockContext: Context - @Mock private lateinit var mSecureSettings: SecureSettings - @Mock private lateinit var mSystemProperties: SystemPropertiesHelper - @Mock private lateinit var mResources: Resources - @Mock private lateinit var mDumpManager: DumpManager - @Mock private lateinit var mBarService: IStatusBarService - private val mFlagMap = mutableMapOf<Int, Flag<*>>() - private lateinit var mBroadcastReceiver: BroadcastReceiver - private lateinit var mClearCacheAction: Consumer<Int> + @Mock private lateinit var flagManager: FlagManager + @Mock private lateinit var mockContext: Context + @Mock private lateinit var secureSettings: SecureSettings + @Mock private lateinit var systemProperties: SystemPropertiesHelper + @Mock private lateinit var resources: Resources + @Mock private lateinit var dumpManager: DumpManager + @Mock private lateinit var commandRegistry: CommandRegistry + @Mock private lateinit var barService: IStatusBarService + @Mock private lateinit var pw: PrintWriter + private val flagMap = mutableMapOf<Int, Flag<*>>() + private lateinit var broadcastReceiver: BroadcastReceiver + private lateinit var clearCacheAction: Consumer<Int> private val teamfoodableFlagA = BooleanFlag(500, false, true) private val teamfoodableFlagB = BooleanFlag(501, true, true) @@ -73,34 +81,35 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) - mFlagMap.put(teamfoodableFlagA.id, teamfoodableFlagA) - mFlagMap.put(teamfoodableFlagB.id, teamfoodableFlagB) + flagMap.put(teamfoodableFlagA.id, teamfoodableFlagA) + flagMap.put(teamfoodableFlagB.id, teamfoodableFlagB) mFeatureFlagsDebug = FeatureFlagsDebug( - mFlagManager, - mMockContext, - mSecureSettings, - mSystemProperties, - mResources, - mDumpManager, - mFlagMap, - mBarService + flagManager, + mockContext, + secureSettings, + systemProperties, + resources, + dumpManager, + flagMap, + commandRegistry, + barService ) - verify(mFlagManager).onSettingsChangedAction = any() - mBroadcastReceiver = withArgCaptor { - verify(mMockContext).registerReceiver(capture(), any(), nullable(), nullable(), + verify(flagManager).onSettingsChangedAction = any() + broadcastReceiver = withArgCaptor { + verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(), any()) } - mClearCacheAction = withArgCaptor { - verify(mFlagManager).clearCacheAction = capture() + clearCacheAction = withArgCaptor { + verify(flagManager).clearCacheAction = capture() } - whenever(mFlagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" } + whenever(flagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" } } @Test fun testReadBooleanFlag() { // Remember that the TEAMFOOD flag is id#1 and has special behavior. - whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) - whenever(mFlagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false) + whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) + whenever(flagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false) assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(2, true))).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(3, false))).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(4, true))).isFalse() @@ -109,7 +118,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testTeamFoodFlag_False() { - whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false) + whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false) assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue() @@ -120,7 +129,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testTeamFoodFlag_True() { - whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) + whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue() @@ -131,11 +140,11 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testTeamFoodFlag_Overridden() { - whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any())) + whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any())) .thenReturn(true) - whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any())) + whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any())) .thenReturn(false) - whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) + whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse() @@ -146,14 +155,14 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testReadResourceBooleanFlag() { - whenever(mResources.getBoolean(1001)).thenReturn(false) - whenever(mResources.getBoolean(1002)).thenReturn(true) - whenever(mResources.getBoolean(1003)).thenReturn(false) - whenever(mResources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() } - whenever(mResources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() } + whenever(resources.getBoolean(1001)).thenReturn(false) + whenever(resources.getBoolean(1002)).thenReturn(true) + whenever(resources.getBoolean(1003)).thenReturn(false) + whenever(resources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() } + whenever(resources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() } - whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) - whenever(mFlagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false) + whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) + whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false) assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(1, 1001))).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, 1002))).isTrue() @@ -171,7 +180,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testReadSysPropBooleanFlag() { - whenever(mSystemProperties.getBoolean(anyString(), anyBoolean())).thenAnswer { + whenever(systemProperties.getBoolean(anyString(), anyBoolean())).thenAnswer { if ("b".equals(it.getArgument<String?>(0))) { return@thenAnswer true } @@ -187,8 +196,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testReadStringFlag() { - whenever(mFlagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo") - whenever(mFlagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar") + whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo") + whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar") assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "biz"))).isEqualTo("biz") assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "baz"))).isEqualTo("baz") assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "buz"))).isEqualTo("foo") @@ -197,16 +206,16 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testReadResourceStringFlag() { - whenever(mResources.getString(1001)).thenReturn("") - whenever(mResources.getString(1002)).thenReturn("resource2") - whenever(mResources.getString(1003)).thenReturn("resource3") - whenever(mResources.getString(1004)).thenReturn(null) - whenever(mResources.getString(1005)).thenAnswer { throw NameNotFoundException() } - whenever(mResources.getString(1006)).thenAnswer { throw NameNotFoundException() } + whenever(resources.getString(1001)).thenReturn("") + whenever(resources.getString(1002)).thenReturn("resource2") + whenever(resources.getString(1003)).thenReturn("resource3") + whenever(resources.getString(1004)).thenReturn(null) + whenever(resources.getString(1005)).thenAnswer { throw NameNotFoundException() } + whenever(resources.getString(1006)).thenAnswer { throw NameNotFoundException() } - whenever(mFlagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3") - whenever(mFlagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4") - whenever(mFlagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6") + whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3") + whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4") + whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6") assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(1, 1001))).isEqualTo("") assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(2, 1002))).isEqualTo("resource2") @@ -232,16 +241,16 @@ class FeatureFlagsDebugTest : SysuiTestCase() { addFlag(StringFlag(3, "flag3")) addFlag(ResourceStringFlag(4, 1004)) - mBroadcastReceiver.onReceive(mMockContext, null) - mBroadcastReceiver.onReceive(mMockContext, Intent()) - mBroadcastReceiver.onReceive(mMockContext, Intent("invalid action")) - mBroadcastReceiver.onReceive(mMockContext, Intent(FlagManager.ACTION_SET_FLAG)) + broadcastReceiver.onReceive(mockContext, null) + broadcastReceiver.onReceive(mockContext, Intent()) + broadcastReceiver.onReceive(mockContext, Intent("invalid action")) + broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG)) setByBroadcast(0, false) // unknown id does nothing setByBroadcast(1, "string") // wrong type does nothing setByBroadcast(2, 123) // wrong type does nothing setByBroadcast(3, false) // wrong type does nothing setByBroadcast(4, 123) // wrong type does nothing - verifyNoMoreInteractions(mFlagManager, mSecureSettings) + verifyNoMoreInteractions(flagManager, secureSettings) } @Test @@ -249,15 +258,15 @@ class FeatureFlagsDebugTest : SysuiTestCase() { addFlag(BooleanFlag(1, false)) // trying to erase an id not in the map does noting - mBroadcastReceiver.onReceive( - mMockContext, + broadcastReceiver.onReceive( + mockContext, Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 0) ) - verifyNoMoreInteractions(mFlagManager, mSecureSettings) + verifyNoMoreInteractions(flagManager, secureSettings) // valid id with no value puts empty string in the setting - mBroadcastReceiver.onReceive( - mMockContext, + broadcastReceiver.onReceive( + mockContext, Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 1) ) verifyPutData(1, "", numReads = 0) @@ -298,48 +307,102 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun testSetFlagClearsCache() { val flag1 = addFlag(StringFlag(1, "flag1")) - whenever(mFlagManager.readFlagValue<String>(eq(1), any())).thenReturn("original") + whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("original") // gets the flag & cache it assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original") - verify(mFlagManager).readFlagValue(eq(1), eq(StringFlagSerializer)) + verify(flagManager).readFlagValue(eq(1), eq(StringFlagSerializer)) // hit the cache assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original") - verifyNoMoreInteractions(mFlagManager) + verifyNoMoreInteractions(flagManager) // set the flag setByBroadcast(1, "new") verifyPutData(1, "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2) - whenever(mFlagManager.readFlagValue<String>(eq(1), any())).thenReturn("new") + whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("new") assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("new") - verify(mFlagManager, times(3)).readFlagValue(eq(1), eq(StringFlagSerializer)) + verify(flagManager, times(3)).readFlagValue(eq(1), eq(StringFlagSerializer)) + } + + @Test + fun testRegisterCommand() { + verify(commandRegistry).registerCommand(anyString(), any()) + } + + @Test + fun testNoOpCommand() { + val cmd = captureCommand() + + cmd.execute(pw, ArrayList()) + verify(pw, atLeastOnce()).println() + verify(flagManager).readFlagValue<Boolean>(eq(1), any()) + verifyZeroInteractions(secureSettings) + } + + @Test + fun testReadFlagCommand() { + addFlag(BooleanFlag(1, false)) + val cmd = captureCommand() + cmd.execute(pw, listOf("1")) + verify(flagManager).readFlagValue<Boolean>(eq(1), any()) + } + + @Test + fun testSetFlagCommand() { + addFlag(BooleanFlag(1, false)) + val cmd = captureCommand() + cmd.execute(pw, listOf("1", "on")) + verifyPutData(1, "{\"type\":\"boolean\",\"value\":true}") + } + + @Test + fun testToggleFlagCommand() { + addFlag(BooleanFlag(1, true)) + val cmd = captureCommand() + cmd.execute(pw, listOf("1", "toggle")) + verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}", 2) + } + + @Test + fun testEraseFlagCommand() { + addFlag(BooleanFlag(1, true)) + val cmd = captureCommand() + cmd.execute(pw, listOf("1", "erase")) + verify(secureSettings).putStringForUser(eq("key-1"), eq(""), anyInt()) } private fun verifyPutData(id: Int, data: String, numReads: Int = 1) { - inOrder(mFlagManager, mSecureSettings).apply { - verify(mFlagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>()) - verify(mFlagManager).idToSettingsKey(eq(id)) - verify(mSecureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt()) - verify(mFlagManager).dispatchListenersAndMaybeRestart(eq(id), any()) + inOrder(flagManager, secureSettings).apply { + verify(flagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>()) + verify(flagManager).idToSettingsKey(eq(id)) + verify(secureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt()) + verify(flagManager).dispatchListenersAndMaybeRestart(eq(id), any()) }.verifyNoMoreInteractions() - verifyNoMoreInteractions(mFlagManager, mSecureSettings) + verifyNoMoreInteractions(flagManager, secureSettings) } private fun setByBroadcast(id: Int, value: Serializable?) { val intent = Intent(FlagManager.ACTION_SET_FLAG) intent.putExtra(FlagManager.EXTRA_ID, id) intent.putExtra(FlagManager.EXTRA_VALUE, value) - mBroadcastReceiver.onReceive(mMockContext, intent) + broadcastReceiver.onReceive(mockContext, intent) } private fun <F : Flag<*>> addFlag(flag: F): F { - val old = mFlagMap.put(flag.id, flag) + val old = flagMap.put(flag.id, flag) check(old == null) { "Flag ${flag.id} already registered" } return flag } + private fun captureCommand(): Command { + val captor = argumentCaptor<Function0<Command>>() + verify(commandRegistry).registerCommand(anyString(), capture(captor)) + + return captor.value.invoke() + } + @Test fun testDump() { val flag1 = BooleanFlag(1, true) @@ -350,10 +413,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() { val flag6 = ResourceStringFlag(6, 1006) val flag7 = ResourceStringFlag(7, 1007) - whenever(mResources.getBoolean(1002)).thenReturn(true) - whenever(mResources.getString(1006)).thenReturn("resource1006") - whenever(mResources.getString(1007)).thenReturn("resource1007") - whenever(mFlagManager.readFlagValue(eq(7), eq(StringFlagSerializer))) + whenever(resources.getBoolean(1002)).thenReturn(true) + whenever(resources.getString(1006)).thenReturn("resource1006") + whenever(resources.getString(1007)).thenReturn("resource1007") + whenever(flagManager.readFlagValue(eq(7), eq(StringFlagSerializer))) .thenReturn("override7") // WHEN the flags have been accessed diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 74f1393ed457..607a873a73d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -373,17 +373,12 @@ public class MediaControlPanelTest : SysuiTestCase() { private fun initRecommendationViewHolderMocks() { whenever(recommendationViewHolder.recommendations).thenReturn(view) whenever(recommendationViewHolder.cardIcon).thenReturn(appIcon) - whenever(recommendationViewHolder.cardText).thenReturn(titleText) // Add a recommendation item coverItem = ImageView(context).also { it.setId(R.id.media_cover1) } whenever(coverContainer.id).thenReturn(R.id.media_cover1_container) whenever(recommendationViewHolder.mediaCoverItems).thenReturn(listOf(coverItem)) whenever(recommendationViewHolder.mediaCoverContainers).thenReturn(listOf(coverContainer)) - whenever(recommendationViewHolder.mediaCoverItemsResIds) - .thenReturn(listOf(R.id.media_cover1)) - whenever(recommendationViewHolder.mediaCoverContainersResIds) - .thenReturn(listOf(R.id.media_cover1_container)) // Long press menu whenever(recommendationViewHolder.settings).thenReturn(settings) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index bc4b2a6f5247..5acae4859ee8 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -154,7 +154,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static final String TAG = "AppWidgetServiceImpl"; private static final boolean DEBUG = false; - private static final boolean DEBUG_PROVIDER_INFO_CACHE = true; + static final boolean DEBUG_PROVIDER_INFO_CACHE = true; private static final String OLD_KEYGUARD_HOST_PACKAGE = "android"; private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard"; @@ -2001,6 +2001,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } + @GuardedBy("mLock") private void scheduleNotifyProviderChangedLocked(Widget widget) { long requestId = UPDATE_COUNTER.incrementAndGet(); if (widget != null) { @@ -2330,6 +2331,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku sendBroadcastAsUser(intent, widget.provider.id.getProfile()); } + @GuardedBy("mLock") private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) { AppWidgetProviderInfo info = provider.getInfoLocked(mContext); if (info.updatePeriodMillis > 0) { @@ -3433,6 +3435,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku * * @return whether any providers were updated */ + @GuardedBy("mLock") private boolean updateProvidersForPackageLocked(String packageName, int userId, Set<ProviderId> removedProviders) { boolean providersUpdated = false; @@ -4218,6 +4221,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku /** * Adds all pending updates in {@param outUpdates} keys by the update time. */ + @GuardedBy("mLock") public void getPendingUpdatesForIdLocked(Context context, int appWidgetId, LongSparseArray<PendingHostUpdate> outUpdates) { long updateSequenceNo = lastWidgetUpdateSequenceNo; diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java index 297575ca168f..6a5dcc8c5945 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java @@ -22,6 +22,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.os.Build; import android.text.TextUtils; +import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -33,6 +34,8 @@ import java.util.Objects; */ public class AppWidgetXmlUtil { + private static final String TAG = "AppWidgetXmlUtil"; + private static final String ATTR_MIN_WIDTH = "min_width"; private static final String ATTR_MIN_HEIGHT = "min_height"; private static final String ATTR_MIN_RESIZE_WIDTH = "min_resize_width"; @@ -77,7 +80,11 @@ public class AppWidgetXmlUtil { if (info.configure != null) { out.attribute(null, ATTR_CONFIGURE, info.configure.flattenToShortString()); } - out.attribute(null, ATTR_LABEL, info.label); + if (info.label != null) { + out.attribute(null, ATTR_LABEL, info.label); + } else if (AppWidgetServiceImpl.DEBUG_PROVIDER_INFO_CACHE) { + Slog.e(TAG, "Label is empty in " + info.provider); + } out.attributeInt(null, ATTR_ICON, info.icon); out.attributeInt(null, ATTR_PREVIEW_IMAGE, info.previewImage); out.attributeInt(null, ATTR_PREVIEW_LAYOUT, info.previewLayout); diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index ac0944be9739..b4c107c1a2c1 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -671,6 +671,9 @@ public class CompanionDeviceManagerService extends SystemService { association = AssociationInfo.builder(association) .setNotifyOnDeviceNearby(active) .build(); + // Do not need to call {@link BleCompanionDeviceScanner#restartScan()} since it will + // trigger {@link BleCompanionDeviceScanner#restartScan(int, AssociationInfo)} when + // an application sets/unsets the mNotifyOnDeviceNearby flag. mAssociationStore.updateAssociation(association); // TODO(b/218615198): correctly handle the case when the device is currently present. diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java index 33301b180619..ad09f7cd3dde 100644 --- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java +++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java @@ -194,6 +194,8 @@ class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener { // Collect MAC addresses from all associations. final Set<String> macAddresses = new HashSet<>(); for (AssociationInfo association : mAssociationStore.getAssociations()) { + if (!association.isNotifyOnDeviceNearby()) continue; + // Beware that BT stack does not consider low-case MAC addresses valid, while // MacAddress.toString() return a low-case String. final String macAddress = association.getDeviceMacAddressAsString(); diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index 1f8ef8226c32..877ee8218ea6 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -441,6 +441,7 @@ public class BinaryTransparencyService extends SystemService { final JobInfo jobInfo = new JobInfo.Builder(COMPUTE_APEX_MODULE_SHA256_JOB_ID, new ComponentName(context, UpdateMeasurementsJobService.class)) .setRequiresDeviceIdle(true) + .setRequiresCharging(true) .build(); if (jobScheduler.schedule(jobInfo) != JobScheduler.RESULT_SUCCESS) { Slog.e(TAG, "Failed to schedule job to update binary measurements."); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 210532a88a8c..eefeee3918b3 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -87,6 +87,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -172,7 +173,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnNetworkProvider mNetworkProvider; @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; - @NonNull private final BroadcastReceiver mPkgChangeReceiver; + @NonNull private final BroadcastReceiver mVcnBroadcastReceiver; @NonNull private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback(); @@ -217,28 +218,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); - mPkgChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (Intent.ACTION_PACKAGE_ADDED.equals(action) - || Intent.ACTION_PACKAGE_REPLACED.equals(action) - || Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - mTelephonySubscriptionTracker.handleSubscriptionsChanged(); - } else { - Log.wtf(TAG, "received unexpected intent: " + action); - } - } - }; + mVcnBroadcastReceiver = new VcnBroadcastReceiver(); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver( - mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler); + mVcnBroadcastReceiver, intentFilter, null /* broadcastPermission */, mHandler); // Run on handler to ensure I/O does not block system server startup mHandler.post(() -> { @@ -443,6 +433,53 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); } + private class VcnBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + switch (action) { + case Intent.ACTION_PACKAGE_ADDED: // Fallthrough + case Intent.ACTION_PACKAGE_REPLACED: // Fallthrough + case Intent.ACTION_PACKAGE_REMOVED: + // Reevaluate subscriptions + mTelephonySubscriptionTracker.handleSubscriptionsChanged(); + + break; + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + final String pkgName = intent.getData().getSchemeSpecificPart(); + + if (pkgName == null || pkgName.isEmpty()) { + logWtf("Package name was empty or null for intent with action" + action); + return; + } + + // Clear configs for the packages that had data cleared, or removed. + synchronized (mLock) { + final List<ParcelUuid> toRemove = new ArrayList<>(); + for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) { + if (pkgName.equals(entry.getValue().getProvisioningPackageName())) { + toRemove.add(entry.getKey()); + } + } + + for (ParcelUuid subGrp : toRemove) { + stopAndClearVcnConfigInternalLocked(subGrp); + } + + if (!toRemove.isEmpty()) { + writeConfigsToDiskLocked(); + } + } + + break; + default: + Slog.wtf(TAG, "received unexpected intent: " + action); + } + } + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -504,6 +541,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Map<ParcelUuid, Set<Integer>> currSubGrpMappings = getSubGroupToSubIdMappings(mLastSnapshot); if (!currSubGrpMappings.equals(oldSubGrpMappings)) { + garbageCollectAndWriteVcnConfigsLocked(); notifyAllPolicyListenersLocked(); } } @@ -645,6 +683,39 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } + private void enforceCarrierPrivilegeOrProvisioningPackage( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Only apps running in the primary (system) user are allowed to configure the VCN. This is + // in line with Telephony's behavior with regards to binding to a Carrier App provided + // CarrierConfigService. + enforcePrimaryUser(); + + if (isProvisioningPackageForConfig(subscriptionGroup, pkg)) { + return; + } + + // Must NOT be called from cleared binder identity, since this checks user calling identity + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, pkg); + } + + private boolean isProvisioningPackageForConfig( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Try-finally to return early if matching owned subscription found. + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + final VcnConfig config = mConfigs.get(subscriptionGroup); + if (config != null && pkg.equals(config.getProvisioningPackageName())) { + return true; + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + + return false; + } + /** * Clears the VcnManagementService for a given subscription group. * @@ -658,31 +729,56 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); + enforceCarrierPrivilegeOrProvisioningPackage(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { - mConfigs.remove(subscriptionGroup); - final boolean vcnExists = mVcns.containsKey(subscriptionGroup); + stopAndClearVcnConfigInternalLocked(subscriptionGroup); + writeConfigsToDiskLocked(); + } + }); + } - stopVcnLocked(subscriptionGroup); + private void stopAndClearVcnConfigInternalLocked(@NonNull ParcelUuid subscriptionGroup) { + mConfigs.remove(subscriptionGroup); + final boolean vcnExists = mVcns.containsKey(subscriptionGroup); - if (vcnExists) { - // TODO(b/181789060): invoke asynchronously after Vcn notifies through - // VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); - } + stopVcnLocked(subscriptionGroup); - writeConfigsToDiskLocked(); + if (vcnExists) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through + // VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); + } + } + + private void garbageCollectAndWriteVcnConfigsLocked() { + final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); + + boolean shouldWrite = false; + + final Iterator<ParcelUuid> configsIterator = mConfigs.keySet().iterator(); + while (configsIterator.hasNext()) { + final ParcelUuid subGrp = configsIterator.next(); + + final List<SubscriptionInfo> subscriptions = subMgr.getSubscriptionsInGroup(subGrp); + if (subscriptions == null || subscriptions.isEmpty()) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + configsIterator.remove(); + shouldWrite = true; } - }); + } + + if (shouldWrite) { + writeConfigsToDiskLocked(); + } } /** * Retrieves the list of subscription groups with configured VcnConfigs * - * <p>Limited to subscription groups for which the caller is carrier privileged. + * <p>Limited to subscription groups for which the caller had configured. * * <p>Implements the IVcnManagementService Binder interface. */ @@ -698,7 +794,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { final List<ParcelUuid> result = new ArrayList<>(); synchronized (mLock) { for (ParcelUuid subGrp : mConfigs.keySet()) { - if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) { + if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName) + || isProvisioningPackageForConfig(subGrp, opPkgName)) { result.add(subGrp); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java new file mode 100644 index 000000000000..1b24aa896652 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 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.server.biometrics.sensors; + +import static android.hardware.biometrics.BiometricStateListener.STATE_AUTH_OTHER; +import static android.hardware.biometrics.BiometricStateListener.STATE_BP_AUTH; +import static android.hardware.biometrics.BiometricStateListener.STATE_ENROLLING; +import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE; +import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH; + +import android.annotation.NonNull; +import android.hardware.biometrics.BiometricStateListener; +import android.hardware.biometrics.IBiometricStateListener; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.Utils; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * A callback for receiving notifications about biometric sensor state changes. + */ +public class BiometricStateCallback implements ClientMonitorCallback { + + private static final String TAG = "BiometricStateCallback"; + + @NonNull + private final CopyOnWriteArrayList<IBiometricStateListener> + mBiometricStateListeners = new CopyOnWriteArrayList<>(); + + private @BiometricStateListener.State int mBiometricState; + + public BiometricStateCallback() { + mBiometricState = STATE_IDLE; + } + + public int getBiometricState() { + return mBiometricState; + } + + @Override + public void onClientStarted(@NonNull BaseClientMonitor client) { + final int previousBiometricState = mBiometricState; + + if (client instanceof AuthenticationClient) { + final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client; + if (authClient.isKeyguard()) { + mBiometricState = STATE_KEYGUARD_AUTH; + } else if (authClient.isBiometricPrompt()) { + mBiometricState = STATE_BP_AUTH; + } else { + mBiometricState = STATE_AUTH_OTHER; + } + } else if (client instanceof EnrollClient) { + mBiometricState = STATE_ENROLLING; + } else { + Slog.w(TAG, "Other authentication client: " + Utils.getClientName(client)); + mBiometricState = STATE_IDLE; + } + + Slog.d(TAG, "State updated from " + previousBiometricState + " to " + mBiometricState + + ", client " + client); + notifyBiometricStateListeners(mBiometricState); + } + + @Override + public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) { + mBiometricState = STATE_IDLE; + Slog.d(TAG, "Client finished, state updated to " + mBiometricState + ", client " + + client); + + if (client instanceof EnrollmentModifier) { + EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client; + final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged(); + Slog.d(TAG, "Enrollment state changed: " + enrollmentStateChanged); + if (enrollmentStateChanged) { + notifyAllEnrollmentStateChanged(client.getTargetUserId(), + client.getSensorId(), + enrollmentModifier.hasEnrollments()); + } + } + + notifyBiometricStateListeners(mBiometricState); + } + + private void notifyBiometricStateListeners(@BiometricStateListener.State int newState) { + for (IBiometricStateListener listener : mBiometricStateListeners) { + try { + listener.onStateChanged(newState); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in biometric state change", e); + } + } + } + + /** + * This should be invoked when: + * 1) Enrolled --> None-enrolled + * 2) None-enrolled --> enrolled + * 3) HAL becomes ready + * 4) Listener is registered + */ + public void notifyAllEnrollmentStateChanged(int userId, int sensorId, + boolean hasEnrollments) { + for (IBiometricStateListener listener : mBiometricStateListeners) { + notifyEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments); + } + } + + /** + * Notifies the listener of enrollment state changes. + */ + public void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener, + int userId, int sensorId, boolean hasEnrollments) { + try { + listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + + /** + * Enables clients to register a BiometricStateListener. For example, this is used to forward + * fingerprint sensor state changes to SideFpsEventHandler. + * + * @param listener + */ + public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { + mBiometricStateListeners.add(listener); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 5727ffc468df..97efc7813230 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -42,6 +42,7 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.IBiometricStateListener; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; @@ -55,7 +56,6 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintServiceReceiver; -import android.hardware.fingerprint.IFingerprintStateListener; import android.hardware.fingerprint.ISidefpsController; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Binder; @@ -84,6 +84,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -114,7 +115,7 @@ public class FingerprintService extends SystemService { private final LockPatternUtils mLockPatternUtils; private final FingerprintServiceWrapper mServiceWrapper; @NonNull private final List<ServiceProvider> mServiceProviders; - @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final BiometricStateCallback mBiometricStateCallback; @NonNull private final Handler mHandler; @GuardedBy("mLock") @@ -125,20 +126,20 @@ public class FingerprintService extends SystemService { @NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps; /** - * Registers FingerprintStateListener in list stored by FingerprintService - * @param listener new FingerprintStateListener being added + * Registers BiometricStateListener in list stored by FingerprintService + * @param listener new BiometricStateListener being added */ - public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) { - mFingerprintStateCallback.registerFingerprintStateListener(listener); + public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { + mBiometricStateCallback.registerBiometricStateListener(listener); broadcastCurrentEnrollmentState(listener); } /** * @param listener if non-null, notifies only this listener. if null, notifies all listeners - * in {@link FingerprintStateCallback}. This is slightly ugly, but reduces + * in {@link BiometricStateCallback}. This is slightly ugly, but reduces * redundant code. */ - private void broadcastCurrentEnrollmentState(@Nullable IFingerprintStateListener listener) { + private void broadcastCurrentEnrollmentState(@Nullable IBiometricStateListener listener) { final UserManager um = UserManager.get(getContext()); synchronized (mLock) { // Update the new listener with current state of all sensors @@ -151,10 +152,10 @@ public class FingerprintService extends SystemService { // Defer this work and allow the loop to release the lock sooner mHandler.post(() -> { if (listener != null) { - mFingerprintStateCallback.notifyFingerprintEnrollmentStateChanged( + mBiometricStateCallback.notifyEnrollmentStateChanged( listener, userInfo.id, prop.sensorId, enrolled); } else { - mFingerprintStateCallback.notifyAllFingerprintEnrollmentStateChanged( + mBiometricStateCallback.notifyAllEnrollmentStateChanged( userInfo.id, prop.sensorId, enrolled); } }); @@ -651,7 +652,7 @@ public class FingerprintService extends SystemService { pw.println("Dumping for sensorId: " + props.sensorId + ", provider: " + provider.getClass().getSimpleName()); pw.println("Fps state: " - + mFingerprintStateCallback.getFingerprintState()); + + mBiometricStateCallback.getBiometricState()); provider.dumpInternal(props.sensorId, pw); pw.println(); } @@ -847,12 +848,12 @@ public class FingerprintService extends SystemService { Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, UserHandle.USER_CURRENT) != 0) { fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), - mFingerprintStateCallback, hidlSensor, + mBiometricStateCallback, hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, BiometricContext.getInstance(getContext())); } else { fingerprint21 = Fingerprint21.newInstance(getContext(), - mFingerprintStateCallback, hidlSensor, mHandler, + mBiometricStateCallback, hidlSensor, mHandler, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } mServiceProviders.add(fingerprint21); @@ -875,7 +876,7 @@ public class FingerprintService extends SystemService { try { final SensorProps[] props = fp.getSensorProps(); final FingerprintProvider provider = - new FingerprintProvider(getContext(), mFingerprintStateCallback, props, + new FingerprintProvider(getContext(), mBiometricStateCallback, props, instance, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, BiometricContext.getInstance(getContext())); @@ -1015,8 +1016,8 @@ public class FingerprintService extends SystemService { } @Override - public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) { - FingerprintService.this.registerFingerprintStateListener(listener); + public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) { + FingerprintService.this.registerBiometricStateListener(listener); } } @@ -1028,7 +1029,7 @@ public class FingerprintService extends SystemService { mLockoutResetDispatcher = new LockoutResetDispatcher(context); mLockPatternUtils = new LockPatternUtils(context); mServiceProviders = new ArrayList<>(); - mFingerprintStateCallback = new FingerprintStateCallback(); + mBiometricStateCallback = new BiometricStateCallback(); mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); mSensorProps = new ArrayList<>(); mHandler = new Handler(Looper.getMainLooper()); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java deleted file mode 100644 index 04fd534adb3b..000000000000 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2021 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.server.biometrics.sensors.fingerprint; - -import static android.hardware.fingerprint.FingerprintStateListener.STATE_AUTH_OTHER; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH; - -import android.annotation.NonNull; -import android.hardware.fingerprint.FingerprintStateListener; -import android.hardware.fingerprint.IFingerprintStateListener; -import android.os.RemoteException; -import android.util.Slog; - -import com.android.server.biometrics.Utils; -import com.android.server.biometrics.sensors.AuthenticationClient; -import com.android.server.biometrics.sensors.BaseClientMonitor; -import com.android.server.biometrics.sensors.ClientMonitorCallback; -import com.android.server.biometrics.sensors.EnrollClient; -import com.android.server.biometrics.sensors.EnrollmentModifier; - -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * A callback for receiving notifications about changes in fingerprint state. - */ -public class FingerprintStateCallback implements ClientMonitorCallback { - - @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener> - mFingerprintStateListeners = new CopyOnWriteArrayList<>(); - - private @FingerprintStateListener.State int mFingerprintState; - - public FingerprintStateCallback() { - mFingerprintState = STATE_IDLE; - } - - public int getFingerprintState() { - return mFingerprintState; - } - - @Override - public void onClientStarted(@NonNull BaseClientMonitor client) { - final int previousFingerprintState = mFingerprintState; - - if (client instanceof AuthenticationClient) { - final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client; - if (authClient.isKeyguard()) { - mFingerprintState = STATE_KEYGUARD_AUTH; - } else if (authClient.isBiometricPrompt()) { - mFingerprintState = STATE_BP_AUTH; - } else { - mFingerprintState = STATE_AUTH_OTHER; - } - } else if (client instanceof EnrollClient) { - mFingerprintState = STATE_ENROLLING; - } else { - Slog.w(FingerprintService.TAG, - "Other authentication client: " + Utils.getClientName(client)); - mFingerprintState = STATE_IDLE; - } - - Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState - + " to " + mFingerprintState + ", client " + client); - notifyFingerprintStateListeners(mFingerprintState); - } - - @Override - public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) { - mFingerprintState = STATE_IDLE; - Slog.d(FingerprintService.TAG, - "Client finished, fps state updated to " + mFingerprintState + ", client " - + client); - - if (client instanceof EnrollmentModifier) { - EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client; - final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged(); - Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged); - if (enrollmentStateChanged) { - notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(), - client.getSensorId(), - enrollmentModifier.hasEnrollments()); - } - } - - notifyFingerprintStateListeners(mFingerprintState); - } - - private void notifyFingerprintStateListeners(@FingerprintStateListener.State int newState) { - for (IFingerprintStateListener listener : mFingerprintStateListeners) { - try { - listener.onStateChanged(newState); - } catch (RemoteException e) { - Slog.e(FingerprintService.TAG, "Remote exception in fingerprint state change", e); - } - } - } - - /** - * This should be invoked when: - * 1) Enrolled --> None-enrolled - * 2) None-enrolled --> enrolled - * 3) HAL becomes ready - * 4) Listener is registered - */ - void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId, - boolean hasEnrollments) { - for (IFingerprintStateListener listener : mFingerprintStateListeners) { - notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments); - } - } - - /** - * Notifies the listener of enrollment state changes. - */ - void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener, - int userId, int sensorId, boolean hasEnrollments) { - try { - listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments); - } catch (RemoteException e) { - Slog.e(FingerprintService.TAG, "Remote exception", e); - } - } - - /** - * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward - * updates in fingerprint sensor state to the SideFpNsEventHandler - * - * @param listener - */ - public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) { - mFingerprintStateListeners.add(listener); - } -} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java index 0528cd489ae5..ba7202fec93b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java @@ -32,8 +32,8 @@ import android.util.Slog; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.BaseClientMonitor; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallback; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import java.util.HashSet; @@ -52,7 +52,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub { @NonNull private final Context mContext; private final int mSensorId; @NonNull private final ITestSessionCallback mCallback; - @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final BiometricStateCallback mBiometricStateCallback; @NonNull private final FingerprintProvider mProvider; @NonNull private final Sensor mSensor; @NonNull private final Set<Integer> mEnrollmentIds; @@ -118,13 +118,13 @@ class BiometricTestSessionImpl extends ITestSession.Stub { BiometricTestSessionImpl(@NonNull Context context, int sensorId, @NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintProvider provider, @NonNull Sensor sensor) { mContext = context; mSensorId = sensorId; mCallback = callback; - mFingerprintStateCallback = fingerprintStateCallback; + mBiometricStateCallback = biometricStateCallback; mProvider = provider; mSensor = sensor; mEnrollmentIds = new HashSet<>(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 1fac8a8ce5c9..7d5b77c2d711 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -58,13 +58,13 @@ import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.BaseClientMonitor; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; import com.android.server.biometrics.sensors.InvalidationRequesterClient; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.PerformanceTracker; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import com.android.server.biometrics.sensors.fingerprint.ServiceProvider; @@ -91,7 +91,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi private boolean mTestHalEnabled; @NonNull private final Context mContext; - @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final BiometricStateCallback mBiometricStateCallback; @NonNull private final String mHalInstanceName; @NonNull @VisibleForTesting final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports @@ -141,13 +141,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } public FingerprintProvider(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull SensorProps[] props, @NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher, @NonNull BiometricContext biometricContext) { mContext = context; - mFingerprintStateCallback = fingerprintStateCallback; + mBiometricStateCallback = biometricStateCallback; mHalInstanceName = halInstanceName; mSensors = new SparseArray<>(); mHandler = new Handler(Looper.getMainLooper()); @@ -389,13 +389,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { - mFingerprintStateCallback.onClientStarted(clientMonitor); + mBiometricStateCallback.onClientStarted(clientMonitor); } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { - mFingerprintStateCallback.onClientFinished(clientMonitor, success); + mBiometricStateCallback.onClientFinished(clientMonitor, success); if (success) { scheduleLoadAuthenticatorIdsForUser(sensorId, userId); scheduleInvalidationRequest(sensorId, userId); @@ -425,7 +425,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, mUdfpsOverlayController, isStrongBiometric); - scheduleForSensor(sensorId, client, mFingerprintStateCallback); + scheduleForSensor(sensorId, client, mBiometricStateCallback); }); return id; @@ -447,7 +447,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication, mSensors.get(sensorId).getSensorProperties()); - scheduleForSensor(sensorId, client, mFingerprintStateCallback); + scheduleForSensor(sensorId, client, mBiometricStateCallback); }); } @@ -509,7 +509,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi BiometricsProtoEnums.CLIENT_UNKNOWN), mBiometricContext, mSensors.get(sensorId).getAuthenticatorIds()); - scheduleForSensor(sensorId, client, mFingerprintStateCallback); + scheduleForSensor(sensorId, client, mBiometricStateCallback); }); } @@ -528,7 +528,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi enrolledList, FingerprintUtils.getInstance(sensorId), mSensors.get(sensorId).getAuthenticatorIds()); scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(callback, - mFingerprintStateCallback)); + mBiometricStateCallback)); }); } @@ -680,7 +680,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @Override public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName) { - return mSensors.get(sensorId).createTestSession(callback, mFingerprintStateCallback); + return mSensors.get(sensorId).createTestSession(callback, mBiometricStateCallback); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index 024d611732c1..1dcf4e9528d2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -55,6 +55,7 @@ import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.EnumerateConsumer; import com.android.server.biometrics.sensors.ErrorConsumer; import com.android.server.biometrics.sensors.LockoutCache; @@ -64,7 +65,6 @@ import com.android.server.biometrics.sensors.RemovalConsumer; import com.android.server.biometrics.sensors.StartUserClient; import com.android.server.biometrics.sensors.StopUserClient; import com.android.server.biometrics.sensors.UserAwareBiometricScheduler; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; @@ -527,9 +527,9 @@ public class Sensor { } @NonNull ITestSession createTestSession(@NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + @NonNull BiometricStateCallback biometricStateCallback) { return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, - fingerprintStateCallback, mProvider, this); + biometricStateCallback, mProvider, this); } @NonNull BiometricScheduler getScheduler() { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java index 033855f822a4..a58bb8981cf6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java @@ -31,8 +31,8 @@ import android.util.Slog; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.BaseClientMonitor; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallback; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import java.util.ArrayList; @@ -53,7 +53,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { @NonNull private final Context mContext; private final int mSensorId; @NonNull private final ITestSessionCallback mCallback; - @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final BiometricStateCallback mBiometricStateCallback; @NonNull private final Fingerprint21 mFingerprint21; @NonNull private final Fingerprint21.HalResultController mHalResultController; @NonNull private final Set<Integer> mEnrollmentIds; @@ -119,14 +119,14 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { BiometricTestSessionImpl(@NonNull Context context, int sensorId, @NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull Fingerprint21 fingerprint21, @NonNull Fingerprint21.HalResultController halResultController) { mContext = context; mSensorId = sensorId; mCallback = callback; mFingerprint21 = fingerprint21; - mFingerprintStateCallback = fingerprintStateCallback; + mBiometricStateCallback = biometricStateCallback; mHalResultController = halResultController; mEnrollmentIds = new HashSet<>(); mRandom = new Random(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 1d2a3655021c..52dbe2460e1c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -64,6 +64,7 @@ import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; @@ -73,7 +74,6 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; import com.android.server.biometrics.sensors.PerformanceTracker; import com.android.server.biometrics.sensors.RemovalConsumer; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import com.android.server.biometrics.sensors.fingerprint.ServiceProvider; @@ -105,7 +105,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider private boolean mTestHalEnabled; final Context mContext; - @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final BiometricStateCallback mBiometricStateCallback; private final ActivityTaskManager mActivityTaskManager; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; private final BiometricScheduler mScheduler; @@ -323,7 +323,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @VisibleForTesting Fingerprint21(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @@ -331,7 +331,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @NonNull HalResultController controller, @NonNull BiometricContext biometricContext) { mContext = context; - mFingerprintStateCallback = fingerprintStateCallback; + mBiometricStateCallback = biometricStateCallback; mBiometricContext = biometricContext; mSensorProperties = sensorProps; @@ -362,7 +362,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } public static Fingerprint21 newInstance(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @@ -373,7 +373,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider gestureAvailabilityDispatcher); final HalResultController controller = new HalResultController(sensorProps.sensorId, context, handler, scheduler); - return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler, + return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler, lockoutResetDispatcher, controller, BiometricContext.getInstance(context)); } @@ -604,13 +604,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { - mFingerprintStateCallback.onClientStarted(clientMonitor); + mBiometricStateCallback.onClientStarted(clientMonitor); } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { - mFingerprintStateCallback.onClientFinished(clientMonitor, success); + mBiometricStateCallback.onClientFinished(clientMonitor, success); if (success) { // Update authenticatorIds scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(), @@ -642,7 +642,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, mUdfpsOverlayController, isStrongBiometric); - mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); return id; @@ -666,7 +666,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication, mSensorProperties); - mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); } @@ -708,7 +708,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider createLogger(BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN), mBiometricContext, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); } @@ -728,7 +728,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider createLogger(BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN), mBiometricContext, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); } @@ -754,7 +754,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider public void scheduleInternalCleanup(int sensorId, int userId, @Nullable ClientMonitorCallback callback) { scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback, - mFingerprintStateCallback)); + mBiometricStateCallback)); } private BiometricLogger createLogger(int statsAction, int statsClient) { @@ -967,6 +967,6 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, @NonNull String opPackageName) { return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, - mFingerprintStateCallback, this, mHalResultController); + mBiometricStateCallback, this, mHalResultController); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index a4e343e786c1..485a674dda92 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -41,9 +41,9 @@ import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.util.ArrayList; @@ -245,7 +245,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher, @@ -257,7 +257,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher); final MockHalResultController controller = new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); - return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler, + return new Fingerprint21UdfpsMock(context, biometricStateCallback, sensorProps, scheduler, handler, lockoutResetDispatcher, controller, biometricContext); } @@ -382,14 +382,14 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } private Fingerprint21UdfpsMock(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller, @NonNull BiometricContext biometricContext) { - super(context, fingerprintStateCallback, sensorProps, scheduler, handler, + super(context, biometricStateCallback, sensorProps, scheduler, handler, lockoutResetDispatcher, controller, biometricContext); mScheduler = scheduler; mScheduler.init(this); diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java index af87677ecb66..1fa56bc3e055 100644 --- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java +++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java @@ -47,6 +47,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * Entry point for most GNSS HAL commands and callbacks. @@ -1271,7 +1272,8 @@ public class GnssNative { @NativeEntryPoint boolean isInEmergencySession() { return Binder.withCleanCallingIdentity( - () -> mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec())); + () -> mEmergencyHelper.isInEmergency( + TimeUnit.SECONDS.toMillis(mConfiguration.getEsExtensionSec()))); } /** diff --git a/services/core/java/com/android/server/policy/SideFpsEventHandler.java b/services/core/java/com/android/server/policy/SideFpsEventHandler.java index f36869859170..41d02727d9eb 100644 --- a/services/core/java/com/android/server/policy/SideFpsEventHandler.java +++ b/services/core/java/com/android/server/policy/SideFpsEventHandler.java @@ -16,9 +16,9 @@ package com.android.server.policy; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING; -import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE; +import static android.hardware.biometrics.BiometricStateListener.STATE_BP_AUTH; +import static android.hardware.biometrics.BiometricStateListener.STATE_ENROLLING; +import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,9 +30,9 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; -import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.PowerManager; @@ -67,7 +67,7 @@ public class SideFpsEventHandler { } }; - private @FingerprintStateListener.State int mFingerprintState; + private @BiometricStateListener.State int mBiometricState; SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) { this(context, handler, powerManager, () -> new AlertDialog.Builder(context)); @@ -80,7 +80,7 @@ public class SideFpsEventHandler { mHandler = handler; mPowerManager = powerManager; mDialogSupplier = dialogSupplier; - mFingerprintState = STATE_IDLE; + mBiometricState = STATE_IDLE; mSideFpsEventHandlerReady = new AtomicBoolean(false); // ensure dialog is dismissed if screen goes off for unrelated reasons @@ -108,7 +108,7 @@ public class SideFpsEventHandler { return false; } - switch (mFingerprintState) { + switch (mBiometricState) { case STATE_ENROLLING: case STATE_BP_AUTH: mHandler.post(() -> { @@ -116,7 +116,7 @@ public class SideFpsEventHandler { mDialog.dismiss(); } mDialog = showConfirmDialog(mDialogSupplier.get(), - mPowerManager, eventTime, mFingerprintState, mDialogDismissListener); + mPowerManager, eventTime, mBiometricState, mDialogDismissListener); }); return true; default: @@ -127,9 +127,9 @@ public class SideFpsEventHandler { @NonNull private static Dialog showConfirmDialog(@NonNull AlertDialog.Builder dialogBuilder, @NonNull PowerManager powerManager, long eventTime, - @FingerprintStateListener.State int fingerprintState, + @BiometricStateListener.State int biometricState, @NonNull DialogInterface.OnDismissListener dismissListener) { - final boolean enrolling = fingerprintState == STATE_ENROLLING; + final boolean enrolling = biometricState == STATE_ENROLLING; final int title = enrolling ? R.string.fp_power_button_enrollment_title : R.string.fp_power_button_bp_title; final int message = enrolling ? R.string.fp_power_button_enrollment_message @@ -165,8 +165,8 @@ public class SideFpsEventHandler { /** * Awaits notification from PhoneWindowManager that fingerprint service is ready * to send updates about power button fps sensor state. Then configures a - * FingerprintStateListener to receive and record updates to fps state, and - * registers the FingerprintStateListener in FingerprintManager. + * BiometricStateListener to receive and record updates to fps state, and + * registers the BiometricStateListener in FingerprintManager. */ public void onFingerprintSensorReady() { final PackageManager pm = mContext.getPackageManager(); @@ -182,13 +182,14 @@ public class SideFpsEventHandler { public void onAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { if (fingerprintManager.isPowerbuttonFps()) { - fingerprintManager.registerFingerprintStateListener( - new FingerprintStateListener() { - @Nullable private Runnable mStateRunnable = null; + fingerprintManager.registerBiometricStateListener( + new BiometricStateListener() { + @Nullable + private Runnable mStateRunnable = null; @Override public void onStateChanged( - @FingerprintStateListener.State int newState) { + @BiometricStateListener.State int newState) { if (mStateRunnable != null) { mHandler.removeCallbacks(mStateRunnable); mStateRunnable = null; @@ -198,11 +199,11 @@ public class SideFpsEventHandler { // arrive in any order (success auth & power). Add a // damper when moving to idle in case auth is first if (newState == STATE_IDLE) { - mStateRunnable = () -> mFingerprintState = newState; + mStateRunnable = () -> mBiometricState = newState; mHandler.postDelayed(mStateRunnable, DEBOUNCE_DELAY_MILLIS); } else { - mFingerprintState = newState; + mBiometricState = newState; } } }); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java index 38e8dfa45262..5f88c99b1d1e 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java @@ -24,12 +24,13 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.hardware.fingerprint.FingerprintStateListener; +import android.hardware.biometrics.BiometricStateListener; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import com.android.server.biometrics.sensors.AuthenticationClient; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.EnrollClient; import org.junit.Before; @@ -39,19 +40,19 @@ import org.mockito.MockitoAnnotations; @Presubmit @SmallTest -public class FingerprintStateCallbackTest { +public class BiometricStateCallbackTest { - private FingerprintStateCallback mCallback; + private BiometricStateCallback mCallback; @Mock - FingerprintStateListener mFingerprintStateListener; + BiometricStateListener mBiometricStateListener; @Before public void setup() { MockitoAnnotations.initMocks(this); - mCallback = new FingerprintStateCallback(); - mCallback.registerFingerprintStateListener(mFingerprintStateListener); + mCallback = new BiometricStateCallback(); + mCallback.registerBiometricStateListener(mBiometricStateListener); } @Test @@ -86,10 +87,10 @@ public class FingerprintStateCallbackTest { mCallback.onClientFinished(client, true /* success */); if (expectCallback) { - verify(mFingerprintStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId), + verify(mBiometricStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId), eq(expectedCallbackValue)); } else { - verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), + verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), anyBoolean()); } } @@ -98,7 +99,7 @@ public class FingerprintStateCallbackTest { public void testAuthentication_enrollmentCallbackNeverNotified() { AuthenticationClient<?> client = mock(AuthenticationClient.class); mCallback.onClientFinished(client, true /* success */); - verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), + verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), anyBoolean()); } } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java index 5a1a02eb39c8..c6ddf27f96b2 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java @@ -42,9 +42,9 @@ import androidx.test.filters.SmallTest; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.BiometricScheduler; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.HalClientMonitor; import com.android.server.biometrics.sensors.LockoutResetDispatcher; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import org.junit.Before; @@ -71,7 +71,7 @@ public class FingerprintProviderTest { @Mock private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; @Mock - private FingerprintStateCallback mFingerprintStateCallback; + private BiometricStateCallback mBiometricStateCallback; @Mock private BiometricContext mBiometricContext; @@ -107,7 +107,7 @@ public class FingerprintProviderTest { mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext, - mFingerprintStateCallback, mSensorProps, TAG, mLockoutResetDispatcher, + mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext); } @@ -156,13 +156,13 @@ public class FingerprintProviderTest { TestableFingerprintProvider(@NonNull IFingerprint daemon, @NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull SensorProps[] props, @NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher, @NonNull BiometricContext biometricContext) { - super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher, + super(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext); mDaemon = daemon; } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java index 529f994f2773..b32b89aaefb0 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java @@ -41,8 +41,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.sensors.BiometricScheduler; +import com.android.server.biometrics.sensors.BiometricStateCallback; import com.android.server.biometrics.sensors.LockoutResetDispatcher; -import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import org.junit.Before; import org.junit.Test; @@ -70,7 +70,7 @@ public class Fingerprint21Test { @Mock private BiometricScheduler mScheduler; @Mock - private FingerprintStateCallback mFingerprintStateCallback; + private BiometricStateCallback mBiometricStateCallback; @Mock private BiometricContext mBiometricContext; @@ -102,7 +102,7 @@ public class Fingerprint21Test { componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN, resetLockoutRequiresHardwareAuthToken); - mFingerprint21 = new TestableFingerprint21(mContext, mFingerprintStateCallback, sensorProps, + mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback, sensorProps, mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController, mBiometricContext); } @@ -125,13 +125,13 @@ public class Fingerprint21Test { private static class TestableFingerprint21 extends Fingerprint21 { TestableFingerprint21(@NonNull Context context, - @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull BiometricStateCallback biometricStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller, @NonNull BiometricContext biometricContext) { - super(context, fingerprintStateCallback, sensorProps, scheduler, handler, + super(context, biometricStateCallback, sensorProps, scheduler, handler, lockoutResetDispatcher, controller, biometricContext); } diff --git a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java index 41c7e31147a5..371861f74871 100644 --- a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java @@ -26,9 +26,9 @@ import static org.mockito.Mockito.when; import android.app.AlertDialog; import android.content.pm.PackageManager; +import android.hardware.biometrics.BiometricStateListener; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; -import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.PowerManager; @@ -61,11 +61,11 @@ import java.util.List; public class SideFpsEventHandlerTest { private static final List<Integer> sAllStates = List.of( - FingerprintStateListener.STATE_IDLE, - FingerprintStateListener.STATE_ENROLLING, - FingerprintStateListener.STATE_KEYGUARD_AUTH, - FingerprintStateListener.STATE_BP_AUTH, - FingerprintStateListener.STATE_AUTH_OTHER); + BiometricStateListener.STATE_IDLE, + BiometricStateListener.STATE_ENROLLING, + BiometricStateListener.STATE_KEYGUARD_AUTH, + BiometricStateListener.STATE_BP_AUTH, + BiometricStateListener.STATE_AUTH_OTHER); @Rule public TestableContext mContext = @@ -83,7 +83,7 @@ public class SideFpsEventHandlerTest { private TestLooper mLooper = new TestLooper(); private SideFpsEventHandler mEventHandler; - private FingerprintStateListener mFingerprintStateListener; + private BiometricStateListener mBiometricStateListener; @Before public void setup() { @@ -116,7 +116,7 @@ public class SideFpsEventHandlerTest { setupWithSensor(false /* hasSfps */, true /* initialized */); for (int state : sAllStates) { - setFingerprintState(state); + setBiometricState(state); assertThat(mEventHandler.onSinglePressDetected(200L)).isFalse(); mLooper.dispatchAll(); @@ -129,7 +129,7 @@ public class SideFpsEventHandlerTest { setupWithSensor(true /* hasSfps */, false /* initialized */); for (int state : sAllStates) { - setFingerprintState(state); + setBiometricState(state); assertThat(mEventHandler.onSinglePressDetected(400L)).isFalse(); mLooper.dispatchAll(); @@ -141,10 +141,10 @@ public class SideFpsEventHandlerTest { public void ignoresWhenIdleOrUnknown() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); - setFingerprintState(FingerprintStateListener.STATE_IDLE); + setBiometricState(BiometricStateListener.STATE_IDLE); assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse(); - setFingerprintState(FingerprintStateListener.STATE_AUTH_OTHER); + setBiometricState(BiometricStateListener.STATE_AUTH_OTHER); assertThat(mEventHandler.onSinglePressDetected(90000L)).isFalse(); mLooper.dispatchAll(); @@ -155,7 +155,7 @@ public class SideFpsEventHandlerTest { public void ignoresOnKeyguard() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); - setFingerprintState(FingerprintStateListener.STATE_KEYGUARD_AUTH); + setBiometricState(BiometricStateListener.STATE_KEYGUARD_AUTH); assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse(); mLooper.dispatchAll(); @@ -166,7 +166,7 @@ public class SideFpsEventHandlerTest { public void promptsWhenBPisActive() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); - setFingerprintState(FingerprintStateListener.STATE_BP_AUTH); + setBiometricState(BiometricStateListener.STATE_BP_AUTH); assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue(); mLooper.dispatchAll(); @@ -177,16 +177,16 @@ public class SideFpsEventHandlerTest { public void promptsWhenEnrolling() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); - setFingerprintState(FingerprintStateListener.STATE_ENROLLING); + setBiometricState(BiometricStateListener.STATE_ENROLLING); assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue(); mLooper.dispatchAll(); verify(mAlertDialog).show(); } - private void setFingerprintState(@FingerprintStateListener.State int newState) { - if (mFingerprintStateListener != null) { - mFingerprintStateListener.onStateChanged(newState); + private void setBiometricState(@BiometricStateListener.State int newState) { + if (mBiometricStateListener != null) { + mBiometricStateListener.onStateChanged(newState); mLooper.dispatchAll(); } } @@ -204,10 +204,10 @@ public class SideFpsEventHandlerTest { fpCallbackCaptor.getValue().onAllAuthenticatorsRegistered( List.of(mock(FingerprintSensorPropertiesInternal.class))); if (hasSfps) { - ArgumentCaptor<FingerprintStateListener> captor = ArgumentCaptor.forClass( - FingerprintStateListener.class); - verify(mFingerprintManager).registerFingerprintStateListener(captor.capture()); - mFingerprintStateListener = captor.getValue(); + ArgumentCaptor<BiometricStateListener> captor = ArgumentCaptor.forClass( + BiometricStateListener.class); + verify(mFingerprintManager).registerBiometricStateListener(captor.capture()); + mBiometricStateListener = captor.getValue(); } } } diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index bb98bc0bab53..54b3c400af4f 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -65,6 +65,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -114,18 +115,24 @@ import java.util.UUID; public class VcnManagementServiceTest { private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); + private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2"; private static final String TEST_CB_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName() + ".callback"; private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); + private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2)); private static final VcnConfig TEST_VCN_CONFIG; + private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final int TEST_UID = Process.FIRST_APPLICATION_UID; static { final Context mockConfigContext = mock(Context.class); - doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); + doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext); + + doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName(); + TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext); } private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP = @@ -246,18 +253,24 @@ public class VcnManagementServiceTest { eq(android.Manifest.permission.NETWORK_FACTORY), any()); } + private void setupMockedCarrierPrivilege(boolean isPrivileged) { + setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME); + } + + private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) .getSubscriptionsInGroup(any()); doReturn(mTelMgr) .when(mTelMgr) .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); - doReturn(isPrivileged - ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS - : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) + doReturn( + isPrivileged + ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) .when(mTelMgr) - .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME)); + .checkCarrierPrivilegesForPackage(eq(pkg)); } @Test @@ -414,7 +427,13 @@ public class VcnManagementServiceTest { private BroadcastReceiver getPackageChangeReceiver() { final ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any()); + verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) + && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED) + && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + }), any(), any()); return captor.getValue(); } @@ -539,6 +558,44 @@ public class VcnManagementServiceTest { } @Test + public void testPackageChangeListener_packageDataCleared() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test + public void testPackageChangeListener_packageFullyRemoved() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -578,7 +635,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage"); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2); fail("Expected exception due to mismatched packages in config and method call"); } catch (IllegalArgumentException expected) { verify(mMockPolicyListener, never()).onPolicyChanged(); @@ -678,11 +735,12 @@ public class VcnManagementServiceTest { } @Test - public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception { + public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage() + throws Exception { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } @@ -691,20 +749,32 @@ public class VcnManagementServiceTest { @Test public void testClearVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage"); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } } @Test - public void testClearVcnConfig() throws Exception { + public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception { + // Lose carrier privileges to test that provisioning package is sufficient. + setupMockedCarrierPrivilege(false); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } @Test + public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test public void testClearVcnConfigNotifiesStatusCallback() throws Exception { setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); @@ -755,11 +825,12 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception { - final String badPackage = "IncorrectPackage"; - doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage); + doThrow(new SecurityException()) + .when(mAppOpsMgr) + .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2); try { - mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage); + mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } @@ -767,14 +838,16 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroups() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2); - // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are - // privileged for. + // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are + // privileged for, or are the provisioning package of. triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List<ParcelUuid> subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); - assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); + assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps); } @Test |