diff options
44 files changed, 608 insertions, 128 deletions
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index addd622eef35..17cd18cc4182 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -48,7 +48,8 @@ interface IBiometricAuthenticator { // startPreparedClient(). void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - long requestId, int cookie, boolean allowBackgroundAuthentication); + long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index e2840ec20ff9..0100660669e9 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -74,7 +74,8 @@ interface IFingerprintService { @EnforcePermission("MANAGE_BIOMETRIC") void prepareForAuthentication(IBinder token, long operationId, IBiometricSensorReceiver sensorReceiver, in FingerprintAuthenticateOptions options, long requestId, - int cookie, boolean allowBackgroundAuthentication); + int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager); // Starts authentication with the previously prepared client. @EnforcePermission("MANAGE_BIOMETRIC") diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig new file mode 100644 index 000000000000..7a4c5bc669fc --- /dev/null +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -0,0 +1,8 @@ +package: "com.android.window.flags" + +flag { + name: "nav_bar_transparent_by_default" + namespace: "windowing_frontend" + description: "Make nav bar color transparent by default when targeting SDK 35 or greater" + bug: "232195501" +} diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 3e16df4d7f67..1be916f44f5b 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1160,7 +1160,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mForceWindowDrawsBarBackgrounds, requestedVisibleTypes); boolean oldDrawLegacy = mDrawLegacyNavigationBarBackground; mDrawLegacyNavigationBarBackground = - (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0; + ((requestedVisibleTypes | mLastForceConsumingTypes) + & WindowInsets.Type.navigationBars()) != 0 + && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0; if (oldDrawLegacy != mDrawLegacyNavigationBarBackground) { mDrawLegacyNavigationBarBackgroundHandled = mWindow.onDrawLegacyNavigationBarBackgroundChanged( diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index eabe3a4eca0b..b556150e2ab9 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -142,6 +142,10 @@ <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string> <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]--> <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string> + <!-- Accessibility announcement when the stack of bubbles expands. [CHAR LIMIT=NONE]--> + <string name="bubble_accessibility_announce_expand">expand <xliff:g id="bubble_title" example="Messages">%1$s</xliff:g></string> + <!-- Accessibility announcement when the stack of bubbles collapses. [CHAR LIMIT=NONE]--> + <string name="bubble_accessibility_announce_collapse">collapse <xliff:g id="bubble_title" example="Messages">%1$s</xliff:g></string> <!-- Label for the button that takes the user to the notification settings for the given app. --> <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string> <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] --> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 3f9dcc19dda7..c124b532b89d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -2037,6 +2037,7 @@ public class BubbleStackView extends FrameLayout }); } notifyExpansionChanged(mExpandedBubble, mIsExpanded); + announceExpandForAccessibility(mExpandedBubble, mIsExpanded); } /** @@ -2053,6 +2054,34 @@ public class BubbleStackView extends FrameLayout } } + private void announceExpandForAccessibility(BubbleViewProvider bubble, boolean expanded) { + if (bubble instanceof Bubble) { + String contentDescription = getBubbleContentDescription((Bubble) bubble); + String message = getResources().getString( + expanded + ? R.string.bubble_accessibility_announce_expand + : R.string.bubble_accessibility_announce_collapse, contentDescription); + announceForAccessibility(message); + } + } + + @NonNull + private String getBubbleContentDescription(Bubble bubble) { + final String appName = bubble.getAppName(); + final String title = bubble.getTitle() != null + ? bubble.getTitle() + : getResources().getString(R.string.notification_bubble_title); + + if (appName == null || title.equals(appName)) { + // App bubble title equals the app name, so return only the title to avoid having + // content description like: `<app> from <app>`. + return title; + } else { + return getResources().getString( + R.string.bubble_content_description_single, title, appName); + } + } + private boolean isGestureNavEnabled() { return mContext.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SnapshotWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SnapshotWindowCreator.java index 20c4d5ae5f58..e7e1e0a98550 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SnapshotWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SnapshotWindowCreator.java @@ -35,13 +35,14 @@ class SnapshotWindowCreator { void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo, TaskSnapshot snapshot) { final int taskId = startingWindowInfo.taskInfo.taskId; // Remove any existing starting window for this task before adding. - mStartingWindowRecordManager.removeWindow(taskId, true); + mStartingWindowRecordManager.removeWindow(taskId); final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, startingWindowInfo.appToken, snapshot, mMainExecutor, - () -> mStartingWindowRecordManager.removeWindow(taskId, true)); + () -> mStartingWindowRecordManager.removeWindow(taskId)); if (surface != null) { final SnapshotWindowRecord tView = new SnapshotWindowRecord(surface, - startingWindowInfo.taskInfo.topActivityType, mMainExecutor); + startingWindowInfo.taskInfo.topActivityType, mMainExecutor, + taskId, mStartingWindowRecordManager); mStartingWindowRecordManager.addRecord(taskId, tView); } } @@ -50,8 +51,9 @@ class SnapshotWindowCreator { private final TaskSnapshotWindow mTaskSnapshotWindow; SnapshotWindowRecord(TaskSnapshotWindow taskSnapshotWindow, - int activityType, ShellExecutor removeExecutor) { - super(activityType, removeExecutor); + int activityType, ShellExecutor removeExecutor, int id, + StartingSurfaceDrawer.StartingWindowRecordManager recordManager) { + super(activityType, removeExecutor, id, recordManager); mTaskSnapshotWindow = taskSnapshotWindow; mBGColor = mTaskSnapshotWindow.getBackgroundColor(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java index 4cfbbd971fe3..31fc98b713ab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java @@ -358,7 +358,7 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator { } } if (shouldSaveView) { - mStartingWindowRecordManager.removeWindow(taskId, true); + mStartingWindowRecordManager.removeWindow(taskId); saveSplashScreenRecord(appToken, taskId, view, suggestType); } return shouldSaveView; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 7cbf263f7cb1..e2be1533118a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -188,7 +188,7 @@ public class StartingSurfaceDrawer { final SnapshotRecord record = sRecord instanceof SnapshotRecord ? (SnapshotRecord) sRecord : null; if (record != null && record.hasImeSurface()) { - records.removeWindow(taskId, true); + records.removeWindow(taskId); } } @@ -256,10 +256,15 @@ public class StartingSurfaceDrawer { @WindowConfiguration.ActivityType protected final int mActivityType; protected final ShellExecutor mRemoveExecutor; + private final int mTaskId; + private final StartingWindowRecordManager mRecordManager; - SnapshotRecord(int activityType, ShellExecutor removeExecutor) { + SnapshotRecord(int activityType, ShellExecutor removeExecutor, int taskId, + StartingWindowRecordManager recordManager) { mActivityType = activityType; mRemoveExecutor = removeExecutor; + mTaskId = taskId; + mRecordManager = recordManager; } @Override @@ -301,6 +306,7 @@ public class StartingSurfaceDrawer { @CallSuper protected void removeImmediately() { mRemoveExecutor.removeCallbacks(mScheduledRunnable); + mRecordManager.onRecordRemoved(mTaskId); } } @@ -316,7 +322,7 @@ public class StartingSurfaceDrawer { taskIds[i] = mStartingWindowRecords.keyAt(i); } for (int i = taskSize - 1; i >= 0; --i) { - removeWindow(taskIds[i], true); + removeWindow(taskIds[i]); } } @@ -335,9 +341,13 @@ public class StartingSurfaceDrawer { } } - void removeWindow(int taskId, boolean immediately) { + void removeWindow(int taskId) { mTmpRemovalInfo.taskId = taskId; - removeWindow(mTmpRemovalInfo, immediately); + removeWindow(mTmpRemovalInfo, true/* immediately */); + } + + void onRecordRemoved(int taskId) { + mStartingWindowRecords.remove(taskId); } StartingWindowRecord getRecord(int taskId) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java index 144547885501..fed2f34b5e0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java @@ -92,7 +92,8 @@ class WindowlessSnapshotWindowCreator { final SnapshotWindowRecord record = new SnapshotWindowRecord(mViewHost, wlw.mChildSurface, taskDescription.getBackgroundColor(), snapshot.hasImeSurface(), - runningTaskInfo.topActivityType, removeExecutor); + runningTaskInfo.topActivityType, removeExecutor, + taskId, mStartingWindowRecordManager); mStartingWindowRecordManager.addRecord(taskId, record); info.notifyAddComplete(wlw.mChildSurface); } @@ -104,8 +105,9 @@ class WindowlessSnapshotWindowCreator { SnapshotWindowRecord(SurfaceControlViewHost viewHost, SurfaceControl childSurface, int bgColor, boolean hasImeSurface, int activityType, - ShellExecutor removeExecutor) { - super(activityType, removeExecutor); + ShellExecutor removeExecutor, int id, + StartingSurfaceDrawer.StartingWindowRecordManager recordManager) { + super(activityType, removeExecutor, id, recordManager); mViewHost = viewHost; mChildSurface = childSurface; mBGColor = bgColor; diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index ceb3858eb0b3..a311296dd90c 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -1284,7 +1284,8 @@ public final class AudioFormat implements Parcelable { * {@link AudioFormat#CHANNEL_OUT_SIDE_RIGHT}. * <p> For a valid {@link AudioTrack} channel position mask, * the following conditions apply: - * <br> (1) at most eight channel positions may be used; + * <br> (1) at most {@link AudioSystem#OUT_CHANNEL_COUNT_MAX} channel positions may be + * used; * <br> (2) right/left pairs should be matched. * <p> For input or {@link AudioRecord}, the mask should be * {@link AudioFormat#CHANNEL_IN_MONO} or diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt index 31e7d7c7c6ba..73b366ef57bc 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/PunchHole.kt @@ -72,15 +72,16 @@ internal class PunchHole( } private fun DrawScope.drawHole(bounds: Element) { + val boundsSize = bounds.lastSize.toSize() if (shape == RectangleShape) { - drawRect(Color.Black, blendMode = BlendMode.DstOut) + drawRect(Color.Black, size = boundsSize, blendMode = BlendMode.DstOut) return } // TODO(b/290184746): Cache outline if the size of bounds does not change. drawOutline( shape.createOutline( - bounds.lastSize.toSize(), + boundsSize, layoutDirection, this, ), diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt new file mode 100644 index 000000000000..1a03481b9fca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt @@ -0,0 +1,26 @@ +package com.android.systemui.qs.tiles.base.interactor + +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow + +/** + * Provides data and availability for the tile. In most cases it would delegate data retrieval to + * repository, manager, controller or a combination of those. Avoid doing long running operations in + * these methods because there is no background thread guarantee. Use [Flow.flowOn] (typically + * with @Background [CoroutineDispatcher]) instead to move the calculations to another thread. + */ +interface QSTileDataInteractor<DATA_TYPE> { + + /** + * Returns the data to be mapped to [QSTileState]. Make sure to start the flow [Flow.onStart] + * with the current state to update the tile as soon as possible. + */ + fun tileData(qsTileDataRequest: QSTileDataRequest): Flow<DATA_TYPE> + + /** + * Returns tile availability - whether this device currently supports this tile. Make sure to + * start the flow [Flow.onStart] with the current state to update the tile as soon as possible. + */ + fun availability(): Flow<Boolean> +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt new file mode 100644 index 000000000000..82897044f06c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt @@ -0,0 +1,6 @@ +package com.android.systemui.qs.tiles.base.interactor + +data class QSTileDataRequest( + val userId: Int, + val trigger: StateUpdateTrigger, +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt new file mode 100644 index 000000000000..8569fc73adb4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt @@ -0,0 +1,13 @@ +package com.android.systemui.qs.tiles.base.interactor + +import android.annotation.WorkerThread +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction + +interface QSTileUserActionInteractor<DATA_TYPE> { + + /** + * Processes user input based on [userAction] and [currentData]. It's safe to run long running + * computations inside this function in this. + */ + @WorkerThread suspend fun handleInput(userAction: QSTileUserAction, currentData: DATA_TYPE) +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt new file mode 100644 index 000000000000..ed7ec8e32de4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt @@ -0,0 +1,11 @@ +package com.android.systemui.qs.tiles.base.interactor + +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction + +sealed interface StateUpdateTrigger { + class UserAction<T>(val action: QSTileUserAction, val tileState: QSTileState, val tileData: T) : + StateUpdateTrigger + data object ForceUpdate : StateUpdateTrigger + data object InitialRequest : StateUpdateTrigger +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt new file mode 100644 index 000000000000..a5eaac154230 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt @@ -0,0 +1,14 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.graphics.drawable.Icon +import com.android.systemui.qs.pipeline.shared.TileSpec + +data class QSTileConfig( + val tileSpec: TileSpec, + val tileIcon: Icon, + val tileLabel: CharSequence, +// TODO(b/299908705): Fill necessary params +/* +val instanceId: InstanceId, + */ +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt new file mode 100644 index 000000000000..39db7038bfa2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt @@ -0,0 +1,6 @@ +package com.android.systemui.qs.tiles.viewmodel + +enum class QSTileLifecycle { + ON_CREATE, + ON_DESTROY, +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt new file mode 100644 index 000000000000..53f9edfb954c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt @@ -0,0 +1,18 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.graphics.drawable.Icon + +data class QSTileState( + val icon: Icon, + val label: CharSequence, +// TODO(b/299908705): Fill necessary params +/* + val subtitle: CharSequence = "", + val activeState: ActivationState = Active, + val enabledState: Enabled = Enabled, + val loopIconAnimation: Boolean = false, + val secondaryIcon: Icon? = null, + val slashState: SlashState? = null, + val supportedActions: Collection<UserAction> = listOf(Click), clicks should be a default action +*/ +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt new file mode 100644 index 000000000000..f1f8f0152c67 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt @@ -0,0 +1,13 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.content.Context +import android.view.View + +sealed interface QSTileUserAction { + + val context: Context + val view: View? + + class Click(override val context: Context, override val view: View?) : QSTileUserAction + class LongClick(override val context: Context, override val view: View?) : QSTileUserAction +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt new file mode 100644 index 000000000000..49077f3f310d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt @@ -0,0 +1,41 @@ +package com.android.systemui.qs.tiles.viewmodel + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +/** + * Represents tiles behaviour logic. This ViewModel is a connection between tile view and data + * layers. + */ +interface QSTileViewModel { + + /** + * State of the tile to be shown by the view. Favor reactive consumption over the + * [StateFlow.value], because there is no guarantee that current value would be available at any + * time. + */ + val state: StateFlow<QSTileState> + + val config: QSTileConfig + + val isAvailable: Flow<Boolean> + + /** + * Handles ViewModel lifecycle. Implementations should be inactive outside of + * [QSTileLifecycle.ON_CREATE] and [QSTileLifecycle.ON_DESTROY] bounds. + */ + fun onLifecycle(lifecycle: QSTileLifecycle) + + /** + * Notifies about the user change. Implementations should avoid using 3rd party userId sources + * and use this value instead. This is to maintain consistent and concurrency-free behaviour + * across different parts of QS. + */ + fun onUserIdChanged(userId: Int) + + /** Triggers emit of the new [QSTileState] in [state]. */ + fun forceUpdate() + + /** Notifies underlying logic about user input. */ + fun onActionPerformed(userAction: QSTileUserAction) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java index ba5fa1df4b15..3d51ab0a2b27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java @@ -45,6 +45,7 @@ public class AospPolicyModule { BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController, DumpManager dumpManager, + BatteryControllerLogger logger, @Main Handler mainHandler, @Background Handler bgHandler) { BatteryController bC = new BatteryControllerImpl( @@ -54,6 +55,7 @@ public class AospPolicyModule { broadcastDispatcher, demoModeController, dumpManager, + logger, mainHandler, bgHandler); bC.init(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 4b515115dd77..41ed76d7edb1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -20,7 +20,6 @@ import static android.os.BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE; import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT; import static android.os.BatteryManager.EXTRA_CHARGING_STATUS; import static android.os.BatteryManager.EXTRA_PRESENT; - import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_QS; import static com.android.systemui.util.DumpUtilsKt.asIndenting; @@ -85,6 +84,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private final PowerManager mPowerManager; private final DemoModeController mDemoModeController; private final DumpManager mDumpManager; + private final BatteryControllerLogger mLogger; private final Handler mMainHandler; private final Handler mBgHandler; protected final Context mContext; @@ -122,6 +122,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController, DumpManager dumpManager, + BatteryControllerLogger logger, @Main Handler mainHandler, @Background Handler bgHandler) { mContext = context; @@ -132,6 +133,8 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC mBroadcastDispatcher = broadcastDispatcher; mDemoModeController = demoModeController; mDumpManager = dumpManager; + mLogger = logger; + mLogger.logBatteryControllerInstance(this); } private void registerReceiver() { @@ -145,6 +148,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void init() { + mLogger.logBatteryControllerInit(this, mHasReceivedBattery); registerReceiver(); if (!mHasReceivedBattery) { // Get initial state. Relying on Sticky behavior until API for getting info. @@ -232,8 +236,13 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void onReceive(final Context context, Intent intent) { final String action = intent.getAction(); + mLogger.logIntentReceived(action); if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - if (mTestMode && !intent.getBooleanExtra("testmode", false)) return; + mLogger.logBatteryChangedIntent(intent); + if (mTestMode && !intent.getBooleanExtra("testmode", false)) { + mLogger.logBatteryChangedSkipBecauseTest(); + return; + } mHasReceivedBattery = true; mLevel = (int) (100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) @@ -275,6 +284,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC fireIsIncompatibleChargingChanged(); } } else if (action.equals(ACTION_LEVEL_TEST)) { + mLogger.logEnterTestMode(); mTestMode = true; mMainHandler.post(new Runnable() { int mCurrentLevel = 0; @@ -286,6 +296,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void run() { if (mCurrentLevel < 0) { + mLogger.logExitTestMode(); mTestMode = false; mTestIntent.putExtra("level", mSavedLevel); mTestIntent.putExtra("plugged", mSavedPluggedIn); @@ -438,6 +449,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } protected void fireBatteryLevelChanged() { + mLogger.logBatteryLevelChangedCallback(mLevel, mPluggedIn, mCharging); synchronized (mChangeCallbacks) { final int N = mChangeCallbacks.size(); for (int i = 0; i < N; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerLogger.kt new file mode 100644 index 000000000000..4a2a2dbad638 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerLogger.kt @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2023 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.systemui.statusbar.policy + +import android.content.Intent +import android.os.BatteryManager.EXTRA_LEVEL +import android.os.BatteryManager.EXTRA_SCALE +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.statusbar.policy.dagger.BatteryControllerLog +import javax.inject.Inject + +/** Detailed, [LogBuffer]-backed logs for [BatteryControllerImpl] */ +@SysUISingleton +class BatteryControllerLogger +@Inject +constructor(@BatteryControllerLog private val logBuffer: LogBuffer) { + fun logBatteryControllerInstance(controller: BatteryController) { + logBuffer.log( + TAG, + LogLevel.DEBUG, + { int1 = System.identityHashCode(controller) }, + { "BatteryController CREATE (${Integer.toHexString(int1)})" } + ) + } + + fun logBatteryControllerInit(controller: BatteryController, hasReceivedBattery: Boolean) { + logBuffer.log( + TAG, + LogLevel.DEBUG, + { + int1 = System.identityHashCode(controller) + bool1 = hasReceivedBattery + }, + { "BatteryController INIT (${Integer.toHexString(int1)}) hasReceivedBattery=$bool1" } + ) + } + + fun logIntentReceived(action: String) { + logBuffer.log(TAG, LogLevel.DEBUG, { str1 = action }, { "Received intent $str1" }) + } + + fun logBatteryChangedIntent(intent: Intent) { + logBuffer.log( + TAG, + LogLevel.DEBUG, + { + int1 = intent.getIntExtra(EXTRA_LEVEL, DEFAULT) + int2 = intent.getIntExtra(EXTRA_SCALE, DEFAULT) + }, + { "Processing BATTERY_CHANGED intent. level=${int1.report()} scale=${int2.report()}" } + ) + } + + fun logBatteryChangedSkipBecauseTest() { + logBuffer.log( + TAG, + LogLevel.DEBUG, + {}, + { "Detected test intent. Will not execute battery level callbacks." } + ) + } + + fun logEnterTestMode() { + logBuffer.log( + TAG, + LogLevel.DEBUG, + {}, + { "Entering test mode for BATTERY_LEVEL_TEST intent" } + ) + } + + fun logExitTestMode() { + logBuffer.log(TAG, LogLevel.DEBUG, {}, { "Exiting test mode" }) + } + + fun logBatteryLevelChangedCallback(level: Int, plugged: Boolean, charging: Boolean) { + logBuffer.log( + TAG, + LogLevel.DEBUG, + { + int1 = level + bool1 = plugged + bool2 = charging + }, + { + "Sending onBatteryLevelChanged callbacks " + + "with level=$int1, plugged=$bool1, charging=$bool2" + } + ) + } + + private fun Int.report(): String = + if (this == DEFAULT) { + "(missing)" + } else { + toString() + } + + companion object { + const val TAG: String = "BatteryControllerLog" + } +} + +// Use a token value so we can determine if we got the default +private const val DEFAULT = -11 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/BatteryControllerLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/BatteryControllerLog.kt new file mode 100644 index 000000000000..5322b3811f95 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/BatteryControllerLog.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 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.systemui.statusbar.policy.dagger + +import javax.inject.Qualifier + +/** Logs for Battery events. See [BatteryControllerImpl] */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class BatteryControllerLog diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index c2a8e701653a..de07a48a2b56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -24,6 +24,8 @@ import com.android.internal.R; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.LogBufferFactory; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.connectivity.AccessPointController; import com.android.systemui.statusbar.connectivity.AccessPointControllerImpl; @@ -31,6 +33,7 @@ import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.NetworkControllerImpl; import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory; import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; +import com.android.systemui.statusbar.policy.BatteryControllerLogger; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.BluetoothControllerImpl; import com.android.systemui.statusbar.policy.CastController; @@ -202,4 +205,13 @@ public interface StatusBarPolicyModule { static DataSaverController provideDataSaverController(NetworkController networkController) { return networkController.getDataSaverController(); } + + /** Provides a log bufffer for BatteryControllerImpl */ + @Provides + @SysUISingleton + @BatteryControllerLog + //TODO(b/300147438): reduce the size of this log buffer + static LogBuffer provideBatteryControllerLog(LogBufferFactory factory) { + return factory.create(BatteryControllerLogger.TAG, 300); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java index cdeb59278851..58d93c98f015 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -17,12 +17,10 @@ package com.android.systemui.statusbar.policy; import static android.os.BatteryManager.EXTRA_PRESENT; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker; import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_QS; - import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -91,6 +89,7 @@ public class BatteryControllerTest extends SysuiTestCase { mBroadcastDispatcher, mDemoModeController, mock(DumpManager.class), + mock(BatteryControllerLogger.class), new Handler(), new Handler()); // Can throw if updateEstimate is called on the main thread diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 2ae3118d7bfa..b9ccbfbf55e7 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -275,7 +275,8 @@ public final class AuthSession implements IBinder.DeathRecipient { } sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie, - mPromptInfo.isAllowBackgroundAuthentication()); + mPromptInfo.isAllowBackgroundAuthentication(), + mPromptInfo.isForLegacyFingerprintManager()); } } @@ -747,7 +748,7 @@ public final class AuthSession implements IBinder.DeathRecipient { Slog.v(TAG, "Confirmed! Modality: " + statsModality() + ", User: " + mUserId + ", IsCrypto: " + isCrypto() - + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT + + ", Client: " + getStatsClient() + ", RequireConfirmation: " + mPreAuthInfo.confirmationRequested + ", State: " + FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED + ", Latency: " + latency @@ -758,7 +759,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mOperationContext, statsModality(), BiometricsProtoEnums.ACTION_UNKNOWN, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + getStatsClient(), mDebugEnabled, latency, FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, @@ -784,7 +785,7 @@ public final class AuthSession implements IBinder.DeathRecipient { + ", User: " + mUserId + ", IsCrypto: " + isCrypto() + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE - + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT + + ", Client: " + getStatsClient() + ", Reason: " + reason + ", Error: " + error + ", Latency: " + latency @@ -796,7 +797,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mOperationContext, statsModality(), BiometricsProtoEnums.ACTION_AUTHENTICATE, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + getStatsClient(), mDebugEnabled, latency, error, @@ -998,6 +999,12 @@ public final class AuthSession implements IBinder.DeathRecipient { } } + private int getStatsClient() { + return mPromptInfo.isForLegacyFingerprintManager() + ? BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER + : BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT; + } + @Override public String toString() { return "State: " + mState diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 937e3f8f8668..42dd36a5c35a 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -106,12 +106,13 @@ public abstract class BiometricSensor { void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - long requestId, int cookie, boolean allowBackgroundAuthentication) + long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager) throws RemoteException { mCookie = cookie; impl.prepareForAuthentication(requireConfirmation, token, sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie, - allowBackgroundAuthentication); + allowBackgroundAuthentication, isForLegacyFingerprintManager); mSensorState = STATE_WAITING_FOR_COOKIE; } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 6ac163121d8c..78c95ad4576b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -283,7 +283,11 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions> } try { - listener.onAuthenticationFailed(getSensorId()); + if (listener != null) { + listener.onAuthenticationFailed(getSensorId()); + } else { + Slog.e(TAG, "Received failed auth, but client was not listening"); + } } catch (RemoteException e) { Slog.e(TAG, "Unable to notify listener", e); mCallback.onClientFinished(this, false); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index fb64bcc3abc1..22110037890f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -62,7 +62,8 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager) throws RemoteException { mFaceService.prepareForAuthentication(requireConfirmation, token, operationId, sensorReceiver, new FaceAuthenticateOptions.Builder() diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index d47a57ad6742..b6fa0c126cd6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -62,7 +62,8 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager) throws RemoteException { mFingerprintService.prepareForAuthentication(token, operationId, sensorReceiver, new FingerprintAuthenticateOptions.Builder() @@ -70,7 +71,7 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub .setUserId(userId) .setOpPackageName(opPackageName) .build(), - requestId, cookie, allowBackgroundAuthentication); + requestId, cookie, allowBackgroundAuthentication, isForLegacyFingerprintManager); } @Override 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 7cc6940f4b9d..5ce0c8b384ef 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 @@ -464,7 +464,8 @@ public class FingerprintService extends SystemService { public void prepareForAuthentication(IBinder token, long operationId, IBiometricSensorReceiver sensorReceiver, @NonNull FingerprintAuthenticateOptions options, - long requestId, int cookie, boolean allowBackgroundAuthentication) { + long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager) { super.prepareForAuthentication_enforcePermission(); final ServiceProvider provider = mRegistry.getProviderForSensor(options.getSensorId()); @@ -473,10 +474,13 @@ public class FingerprintService extends SystemService { return; } + final int statsClient = + isForLegacyFingerprintManager ? BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER + : BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT; final boolean restricted = true; // BiometricPrompt is always restricted provider.scheduleAuthenticate(token, operationId, cookie, new ClientMonitorCallbackConverter(sensorReceiver), options, requestId, - restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + restricted, statsClient, allowBackgroundAuthentication); } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 5c0c3626037a..01d1e378a735 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -59,7 +59,8 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication, + boolean isForLegacyFingerprintManager) throws RemoteException { } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ec071a73d74f..c80661692217 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2047,7 +2047,6 @@ public class NotificationManagerService extends SystemService { protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray(); - boolean mIsInLockDownMode = false; StrongAuthTracker(Context context) { super(context); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index cfc7031d01d7..3c2d0fcb8cdf 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1005,11 +1005,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return; } - if (!mWallpaper.wallpaperUpdating - && mWallpaper.userId == mCurrentUserId) { + if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) { Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent + ", reverting to built-in wallpaper!"); - clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, null); + int which = mIsLockscreenLiveWallpaperEnabled ? mWallpaper.mWhich : FLAG_SYSTEM; + clearWallpaperLocked(which, mWallpaper.userId, null); } } }; @@ -1189,7 +1189,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } else { // Timeout Slog.w(TAG, "Reverting to built-in wallpaper!"); - clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, null); + clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, null); final String flattened = wpService.flattenToString(); EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED, flattened.substring(0, Math.min(flattened.length(), @@ -1228,7 +1228,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } else { if (mLmkLimitRebindRetries <= 0) { Slog.w(TAG, "Reverting to built-in wallpaper due to lmk!"); - clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, null); + clearWallpaperLocked( + mWallpaper.mWhich, mWallpaper.userId, null); mLmkLimitRebindRetries = LMK_RECONNECT_REBIND_RETRIES; return; } @@ -1470,8 +1471,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mCurrentUserId != getChangingUserId()) { return; } - WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); - if (wallpaper != null) { + for (WallpaperData wallpaper: getWallpapers()) { final ComponentName wpService = wallpaper.wallpaperComponent; if (wpService != null && wpService.getPackageName().equals(packageName)) { if (DEBUG_LIVE) { @@ -1483,7 +1483,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper, null)) { Slog.w(TAG, "Wallpaper " + wpService + " no longer available; reverting to default"); - clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null); + int which = mIsLockscreenLiveWallpaperEnabled + ? wallpaper.mWhich : FLAG_SYSTEM; + clearWallpaperLocked(which, wallpaper.userId, null); } } } @@ -1496,13 +1498,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mCurrentUserId != getChangingUserId()) { return; } - WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); - if (wallpaper != null) { - if (wallpaper.wallpaperComponent == null - || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { - return; + for (WallpaperData wallpaper: getWallpapers()) { + if (wallpaper.wallpaperComponent != null + && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { + doPackagesChangedLocked(true, wallpaper); } - doPackagesChangedLocked(true, wallpaper); } } } @@ -1513,8 +1513,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mCurrentUserId != getChangingUserId()) { return; } - WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); - if (wallpaper != null) { + for (WallpaperData wallpaper: getWallpapers()) { if (wallpaper.wallpaperComponent != null && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { if (DEBUG_LIVE) { @@ -1538,8 +1537,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mCurrentUserId != getChangingUserId()) { return false; } - WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); - if (wallpaper != null) { + for (WallpaperData wallpaper: getWallpapers()) { boolean res = doPackagesChangedLocked(doit, wallpaper); changed |= res; } @@ -1553,8 +1551,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mCurrentUserId != getChangingUserId()) { return; } - WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); - if (wallpaper != null) { + for (WallpaperData wallpaper: getWallpapers()) { doPackagesChangedLocked(true, wallpaper); } } @@ -1562,6 +1559,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) { boolean changed = false; + int which = mIsLockscreenLiveWallpaperEnabled ? wallpaper.mWhich : FLAG_SYSTEM; if (wallpaper.wallpaperComponent != null) { int change = isPackageDisappearing(wallpaper.wallpaperComponent .getPackageName()); @@ -1571,7 +1569,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (doit) { Slog.w(TAG, "Wallpaper uninstalled, removing: " + wallpaper.wallpaperComponent); - clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null); + clearWallpaperLocked(which, wallpaper.userId, null); } } } @@ -1592,7 +1590,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } catch (NameNotFoundException e) { Slog.w(TAG, "Wallpaper component gone, removing: " + wallpaper.wallpaperComponent); - clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null); + clearWallpaperLocked(which, wallpaper.userId, null); } } if (wallpaper.nextWallpaperComponent != null @@ -1708,7 +1706,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) { Slog.i(TAG, "Unable to regenerate crop; resetting"); } - clearWallpaperLocked(FLAG_SYSTEM, UserHandle.USER_SYSTEM, null); + int which = isLockscreenLiveWallpaperEnabled() ? wallpaper.mWhich : FLAG_SYSTEM; + clearWallpaperLocked(which, UserHandle.USER_SYSTEM, null); } } else { if (DEBUG) { @@ -1988,12 +1987,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) { if (serviceInfo == null) { - if (wallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)) { - clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null); - clearWallpaperLocked(FLAG_LOCK, wallpaper.userId, reply); - } else { - clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply); - } + clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply); return; } Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked"); @@ -2014,7 +2008,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @Override public void clearWallpaper(String callingPackage, int which, int userId) { - if (DEBUG) Slog.v(TAG, "clearWallpaper"); + if (DEBUG) Slog.v(TAG, "clearWallpaper: " + which); checkPermission(android.Manifest.permission.SET_WALLPAPER); if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { return; @@ -2025,7 +2019,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData data = null; synchronized (mLock) { if (mIsLockscreenLiveWallpaperEnabled) { - clearWallpaperLocked(callingPackage, which, userId); + boolean fromForeground = isFromForegroundApp(callingPackage); + clearWallpaperLocked(which, userId, fromForeground, null); } else { clearWallpaperLocked(which, userId, null); } @@ -2045,7 +2040,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void clearWallpaperLocked(String callingPackage, int which, int userId) { + private void clearWallpaperLocked(int which, int userId, boolean fromForeground, + IRemoteCallback reply) { // Might need to bring it in the first time to establish our rewrite if (!mWallpaperMap.contains(userId)) { @@ -2084,8 +2080,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub finalWhich = which; } - boolean success = withCleanCallingIdentity(() -> setWallpaperComponent( - component, callingPackage, finalWhich, userId)); + // except for the lock case (for which we keep the system wallpaper as-is), force rebind + boolean force = which != FLAG_LOCK; + boolean success = withCleanCallingIdentity(() -> setWallpaperComponentInternal( + component, finalWhich, userId, force, fromForeground, reply)); if (success) return; } catch (IllegalArgumentException e1) { e = e1; @@ -2097,10 +2095,23 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // wallpaper. Slog.e(TAG, "Default wallpaper component not found!", e); withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper)); + if (reply != null) { + try { + reply.sendResult(null); + } catch (RemoteException e1) { + Slog.w(TAG, "Failed to notify callback after wallpaper clear", e1); + } + } } - // TODO(b/266818039) remove this version of the method + // TODO(b/266818039) remove private void clearWallpaperLocked(int which, int userId, IRemoteCallback reply) { + + if (mIsLockscreenLiveWallpaperEnabled) { + clearWallpaperLocked(which, userId, false, reply); + return; + } + if (which != FLAG_SYSTEM && which != FLAG_LOCK) { throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear"); } @@ -2815,6 +2826,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub : new WallpaperData[0]; } + // TODO(b/266818039) remove + private WallpaperData[] getWallpapers() { + WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId); + WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId); + boolean systemValid = systemWallpaper != null; + boolean lockValid = lockWallpaper != null && !isLockscreenLiveWallpaperEnabled(); + return systemValid && lockValid ? new WallpaperData[]{systemWallpaper, lockWallpaper} + : systemValid ? new WallpaperData[]{systemWallpaper} + : lockValid ? new WallpaperData[]{lockWallpaper} + : new WallpaperData[0]; + } + private IWallpaperEngine getEngine(int which, int userId, int displayId) { WallpaperData wallpaperData = findWallpaperAtDisplay(userId, displayId); if (wallpaperData == null) return null; @@ -3272,15 +3295,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub boolean setWallpaperComponent(ComponentName name, String callingPackage, @SetWallpaperFlags int which, int userId) { if (mIsLockscreenLiveWallpaperEnabled) { - return setWallpaperComponentInternal(name, callingPackage, which, userId); + boolean fromForeground = isFromForegroundApp(callingPackage); + return setWallpaperComponentInternal(name, which, userId, false, fromForeground, null); } else { setWallpaperComponentInternalLegacy(name, callingPackage, which, userId); return true; } } - private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage, - @SetWallpaperFlags int which, int userIdIn) { + private boolean setWallpaperComponentInternal(ComponentName name, @SetWallpaperFlags int which, + int userIdIn, boolean force, boolean fromForeground, IRemoteCallback reply) { if (DEBUG) { Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name); } @@ -3294,7 +3318,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final WallpaperData newWallpaper; synchronized (mLock) { - Slog.v(TAG, "setWallpaperComponent name=" + name); + Slog.v(TAG, "setWallpaperComponent name=" + name + ", which = " + which); final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId); if (originalSystemWallpaper == null) { throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); @@ -3317,29 +3341,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub newWallpaper.imageWallpaperPending = false; newWallpaper.mWhich = which; newWallpaper.mSystemWasBoth = systemIsBoth; - newWallpaper.fromForegroundApp = isFromForegroundApp(callingPackage); + newWallpaper.fromForegroundApp = fromForeground; final WallpaperDestinationChangeHandler liveSync = new WallpaperDestinationChangeHandler( newWallpaper); boolean same = changingToSame(name, newWallpaper); - IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { - @Override - public void sendResult(Bundle data) throws RemoteException { - if (DEBUG) { - Slog.d(TAG, "publish system wallpaper changed!"); - } - } - }; /* * If we have a shared system+lock wallpaper, and we reapply the same wallpaper * to system only, force rebind: the current wallpaper will be migrated to lock * and a new engine with the same wallpaper will be applied to system. */ - boolean forceRebind = same && systemIsBoth && which == FLAG_SYSTEM; + boolean forceRebind = force || (same && systemIsBoth && which == FLAG_SYSTEM); bindSuccess = bindWallpaperComponentLocked(name, /* force */ - forceRebind, /* fromUser */ true, newWallpaper, callback); + forceRebind, /* fromUser */ true, newWallpaper, reply); if (bindSuccess) { if (!same) { newWallpaper.primaryColors = null; @@ -3409,7 +3425,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData wallpaper; synchronized (mLock) { - Slog.v(TAG, "setWallpaperComponent name=" + name + ", which=" + which); + Slog.v(TAG, "setWallpaperComponentLegacy name=" + name + ", which=" + which); wallpaper = mWallpaperMap.get(userId); if (wallpaper == null) { throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index daa73db4684d..996d66681d05 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -6505,14 +6505,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** - * @return whether AOD is showing on this display - */ - boolean isAodShowing() { - return mRootWindowContainer.mTaskSupervisor - .getKeyguardController().isAodShowing(mDisplayId); - } - - /** * @return whether this display maintains its own focus and touch mode. */ boolean hasOwnFocus() { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 395ab3a641b4..17bfeb453304 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1677,18 +1677,6 @@ public class DisplayPolicy { } private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) { - // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered - // hidden because it's in the process of hiding, but it's still being shown on screen. - // In that case, we want to continue hiding the IME until the windows have completed - // drawing. This way, we know that the IME can be safely shown since the other windows are - // now shown. - final boolean hideIme = win.mIsImWindow - && (mDisplayContent.isAodShowing() - || (mDisplayContent.isDefaultDisplay && !mWindowManagerDrawComplete)); - if (hideIme) { - return true; - } - if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) { return false; } diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index a27cc3ad9973..ea722b61be6f 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -184,14 +184,31 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } void dispose() { + boolean wasVisible = false; for (int i = mOrganizedTaskFragments.size() - 1; i >= 0; i--) { + final TaskFragment taskFragment = mOrganizedTaskFragments.get(i); + if (taskFragment.isVisibleRequested()) { + wasVisible = true; + } // Cleanup the TaskFragmentOrganizer from all TaskFragments it organized before // removing the windows to prevent it from adding any additional TaskFragment // pending event. - final TaskFragment taskFragment = mOrganizedTaskFragments.get(i); taskFragment.onTaskFragmentOrganizerRemoved(); } + final TransitionController transitionController = mAtmService.getTransitionController(); + if (wasVisible && transitionController.isShellTransitionsEnabled() + && !transitionController.isCollecting()) { + final Task task = mOrganizedTaskFragments.get(0).getTask(); + final boolean containsNonEmbeddedActivity = + task != null && task.getActivity(a -> !a.isEmbedded()) != null; + transitionController.requestStartTransition( + transitionController.createTransition(WindowManager.TRANSIT_CLOSE), + // The task will be removed if all its activities are embedded, then the + // task is the trigger. + containsNonEmbeddedActivity ? null : task, + null /* remoteTransition */, null /* displayChange */); + } // Defer to avoid unnecessary layout when there are multiple TaskFragments removal. mAtmService.deferWindowLayout(); try { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 769be177ce03..0f3daec263e0 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -182,7 +182,8 @@ public class AuthSessionTest { eq(TEST_PACKAGE), eq(TEST_REQUEST_ID), eq(sensor.getCookie()), - anyBoolean() /* allowBackgroundAuthentication */); + anyBoolean() /* allowBackgroundAuthentication */, + anyBoolean() /* isForLegacyFingerprintManager */); } final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie(); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index e79ac0986dc8..0230d77e8e14 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -598,7 +598,8 @@ public class BiometricServiceTest { anyString() /* opPackageName */, eq(TEST_REQUEST_ID), cookieCaptor.capture() /* cookie */, - anyBoolean() /* allowBackgroundAuthentication */); + anyBoolean() /* allowBackgroundAuthentication */, + anyBoolean() /* isForLegacyFingerprintManager */); // onReadyForAuthentication, mAuthSession state OK mBiometricService.mImpl.onReadyForAuthentication(TEST_REQUEST_ID, cookieCaptor.getValue()); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java index 046b01c831b5..9e5a0479ea70 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java @@ -36,6 +36,7 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.content.ComponentName; +import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.common.AuthenticateReason; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.common.OperationContext; @@ -109,6 +110,8 @@ public class FaceAuthenticationClientTest { private ICancellationSignal mCancellationSignal; @Mock private AuthSessionCoordinator mAuthSessionCoordinator; + @Mock + private BiometricManager mBiometricManager; @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; @Captor @@ -119,6 +122,7 @@ public class FaceAuthenticationClientTest { @Before public void setup() { + mContext.addMockSystemService(BiometricManager.class, mBiometricManager); when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer( i -> i.getArgument(0)); when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator); @@ -212,11 +216,44 @@ public class FaceAuthenticationClientTest { .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); } + @Test + public void testOnAuthenticatedFalseWhenListenerIsNull() throws RemoteException { + final FaceAuthenticationClient client = createClientWithNullListener(); + client.start(mCallback); + client.onAuthenticated(new Face("friendly", 1 /* faceId */, 2 /* deviceId */), + false /* authenticated */, new ArrayList<>()); + + verify(mCallback).onClientFinished(client, true); + } + + @Test + public void testOnAuthenticatedTrueWhenListenerIsNull() throws RemoteException { + final FaceAuthenticationClient client = createClientWithNullListener(); + client.start(mCallback); + client.onAuthenticated(new Face("friendly", 1 /* faceId */, 2 /* deviceId */), + true /* authenticated */, new ArrayList<>()); + + verify(mCallback).onClientFinished(client, true); + } + private FaceAuthenticationClient createClient() throws RemoteException { - return createClient(2 /* version */); + return createClient(2 /* version */, mClientMonitorCallbackConverter, + false /* allowBackgroundAuthentication */); + } + + private FaceAuthenticationClient createClientWithNullListener() throws RemoteException { + return createClient(2 /* version */, null /* listener */, + true /* allowBackgroundAuthentication */); } private FaceAuthenticationClient createClient(int version) throws RemoteException { + return createClient(version, mClientMonitorCallbackConverter, + false /* allowBackgroundAuthentication */); + } + + private FaceAuthenticationClient createClient(int version, + ClientMonitorCallbackConverter listener, + boolean allowBackgroundAuthentication) throws RemoteException { when(mHal.getInterfaceVersion()).thenReturn(version); final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback); @@ -229,11 +266,11 @@ public class FaceAuthenticationClientTest { FaceAuthenticateOptions.AUTHENTICATE_REASON_ASSISTANT_VISIBLE) .build(); return new FaceAuthenticationClient(mContext, () -> aidl, mToken, - 2 /* requestId */, mClientMonitorCallbackConverter, OP_ID, + 2 /* requestId */, listener, OP_ID, false /* restricted */, options, 4 /* cookie */, false /* requireConfirmation */, mBiometricLogger, mBiometricContext, true /* isStrongBiometric */, - mUsageStats, null /* mLockoutCache */, false /* allowBackgroundAuthentication */, + mUsageStats, null /* mLockoutCache */, allowBackgroundAuthentication, null /* sensorPrivacyManager */, 0 /* biometricStrength */) { @Override protected ActivityTaskManager getActivityTaskManager() { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index 46af90537c03..8a11e31014d5 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -392,7 +392,6 @@ public class FingerprintAuthenticationClientTest { final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo(); topTask.topActivity = new ComponentName("other", "thing"); when(mActivityTaskManager.getTasks(anyInt())).thenReturn(List.of(topTask)); - when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal); final FingerprintAuthenticationClient client = createClientWithoutBackgroundAuth(); client.start(mCallback); @@ -406,21 +405,50 @@ public class FingerprintAuthenticationClientTest { .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); } + @Test + public void testOnAuthenticatedFalseWhenListenerIsNull() throws RemoteException { + final FingerprintAuthenticationClient client = createClientWithNullListener(); + client.start(mCallback); + client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, + 2 /* deviceId */), false /* authenticated */, new ArrayList<>()); + + verify(mCallback, never()).onClientFinished(eq(client), anyBoolean()); + } + + @Test + public void testOnAuthenticatedTrueWhenListenerIsNull() throws RemoteException { + final FingerprintAuthenticationClient client = createClientWithNullListener(); + client.start(mCallback); + client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, + 2 /* deviceId */), true /* authenticated */, new ArrayList<>()); + + verify(mCallback).onClientFinished(client, true); + } + private FingerprintAuthenticationClient createClient() throws RemoteException { - return createClient(100 /* version */, true /* allowBackgroundAuthentication */); + return createClient(100 /* version */, true /* allowBackgroundAuthentication */, + mClientMonitorCallbackConverter); } private FingerprintAuthenticationClient createClientWithoutBackgroundAuth() throws RemoteException { - return createClient(100 /* version */, false /* allowBackgroundAuthentication */); + return createClient(100 /* version */, false /* allowBackgroundAuthentication */, + mClientMonitorCallbackConverter); } private FingerprintAuthenticationClient createClient(int version) throws RemoteException { - return createClient(version, true /* allowBackgroundAuthentication */); + return createClient(version, true /* allowBackgroundAuthentication */, + mClientMonitorCallbackConverter); + } + + private FingerprintAuthenticationClient createClientWithNullListener() throws RemoteException { + return createClient(100 /* version */, true /* allowBackgroundAuthentication */, + null /* listener */); } private FingerprintAuthenticationClient createClient(int version, - boolean allowBackgroundAuthentication) throws RemoteException { + boolean allowBackgroundAuthentication, ClientMonitorCallbackConverter listener) + throws RemoteException { when(mHal.getInterfaceVersion()).thenReturn(version); final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback); @@ -430,7 +458,7 @@ public class FingerprintAuthenticationClientTest { .setSensorId(9) .build(); return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken, - REQUEST_ID, mClientMonitorCallbackConverter, OP_ID, + REQUEST_ID, listener, OP_ID, false /* restricted */, options, 4 /* cookie */, false /* requireConfirmation */, mBiometricLogger, mBiometricContext, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 5341588c3992..72c3ebece242 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -237,26 +237,27 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { displayInfo.copyFrom(mDisplayInfo); displayInfo.type = Display.TYPE_VIRTUAL; DisplayContent virtualDisplay = createNewDisplay(displayInfo); + final KeyguardController keyguardController = mSupervisor.getKeyguardController(); // Make sure we're starting out with 2 unlocked displays assertEquals(2, mRootWindowContainer.getChildCount()); mRootWindowContainer.forAllDisplays(displayContent -> { assertFalse(displayContent.isKeyguardLocked()); - assertFalse(displayContent.isAodShowing()); + assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); }); // Check that setLockScreenShown locks both displays mAtm.setLockScreenShown(true, true); mRootWindowContainer.forAllDisplays(displayContent -> { assertTrue(displayContent.isKeyguardLocked()); - assertTrue(displayContent.isAodShowing()); + assertTrue(keyguardController.isAodShowing(displayContent.mDisplayId)); }); // Check setLockScreenShown unlocking both displays mAtm.setLockScreenShown(false, false); mRootWindowContainer.forAllDisplays(displayContent -> { assertFalse(displayContent.isKeyguardLocked()); - assertFalse(displayContent.isAodShowing()); + assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); }); } @@ -270,25 +271,26 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; displayInfo.flags = Display.FLAG_OWN_DISPLAY_GROUP | Display.FLAG_ALWAYS_UNLOCKED; DisplayContent newDisplay = createNewDisplay(displayInfo); + final KeyguardController keyguardController = mSupervisor.getKeyguardController(); // Make sure we're starting out with 2 unlocked displays assertEquals(2, mRootWindowContainer.getChildCount()); mRootWindowContainer.forAllDisplays(displayContent -> { assertFalse(displayContent.isKeyguardLocked()); - assertFalse(displayContent.isAodShowing()); + assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); }); // setLockScreenShown should only lock the default display, not the virtual one mAtm.setLockScreenShown(true, true); assertTrue(mDefaultDisplay.isKeyguardLocked()); - assertTrue(mDefaultDisplay.isAodShowing()); + assertTrue(keyguardController.isAodShowing(mDefaultDisplay.mDisplayId)); DisplayContent virtualDisplay = mRootWindowContainer.getDisplayContent( newDisplay.getDisplayId()); assertNotEquals(Display.DEFAULT_DISPLAY, virtualDisplay.getDisplayId()); assertFalse(virtualDisplay.isKeyguardLocked()); - assertFalse(virtualDisplay.isAodShowing()); + assertFalse(keyguardController.isAodShowing(virtualDisplay.mDisplayId)); } /* |