diff options
44 files changed, 581 insertions, 202 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c5a70df0905e..3c5a31cc498b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -43911,6 +43911,7 @@ package android.telephony { field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT = "satellite_screen_off_inactivity_timeout_duration_sec_int"; field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index c09106206c25..109b0a8be7f8 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -60,7 +60,8 @@ public final class BrightnessInfo implements Parcelable { @IntDef(prefix = {"BRIGHTNESS_MAX_REASON_"}, value = { BRIGHTNESS_MAX_REASON_NONE, BRIGHTNESS_MAX_REASON_THERMAL, - BRIGHTNESS_MAX_REASON_POWER_IC + BRIGHTNESS_MAX_REASON_POWER_IC, + BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface BrightnessMaxReason {} diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml new file mode 100644 index 000000000000..c154059f11a5 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z" + android:fillColor="#1C1C14"/> +</vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index 49d9029f14d6..eea3de8e30ca 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -125,7 +125,7 @@ <LinearLayout android:id="@+id/more_actions_pill" android:layout_width="match_parent" - android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height" + android:layout_height="wrap_content" android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin" android:layout_marginStart="1dp" android:orientation="vertical" @@ -139,6 +139,14 @@ android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" android:drawableTint="?androidprv:attr/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton"/> + + <Button + android:id="@+id/new_window_button" + android:contentDescription="@string/new_window_text" + android:text="@string/new_window_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window" + android:drawableTint="?androidprv:attr/materialColorOnSurface" + style="@style/DesktopModeHandleMenuActionButton" /> </LinearLayout> <LinearLayout diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 1eb24580a582..e6807ac5ea94 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -497,7 +497,7 @@ <!-- The maximum height of the handle menu in desktop mode. Four pills (52dp each) plus 2dp spacing between them plus 4dp top padding. --> - <dimen name="desktop_mode_handle_menu_height">218dp</dimen> + <dimen name="desktop_mode_handle_menu_height">270dp</dimen> <!-- The elevation set on the handle menu pills. --> <dimen name="desktop_mode_handle_menu_pill_elevation">1dp</dimen> @@ -508,8 +508,11 @@ <!-- The height of the handle menu's "Windowing" pill in desktop mode. --> <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen> - <!-- The height of the handle menu's "More Actions" pill in desktop mode. --> - <dimen name="desktop_mode_handle_menu_more_actions_pill_height">52dp</dimen> + <!-- The maximum height of the handle menu's "New Window" button in desktop mode. --> + <dimen name="desktop_mode_handle_menu_new_window_height">52dp</dimen> + + <!-- The maximum height of the handle menu's "Screenshot" button in desktop mode. --> + <dimen name="desktop_mode_handle_menu_screenshot_height">52dp</dimen> <!-- The height of the handle menu's "Open in browser" pill in desktop mode. --> <dimen name="desktop_mode_handle_menu_open_in_browser_pill_height">52dp</dimen> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 8669af39747d..0a8166fb1a8d 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -282,6 +282,8 @@ <string name="screenshot_text">Screenshot</string> <!-- Accessibility text for the handle menu open in browser button [CHAR LIMIT=NONE] --> <string name="open_in_browser_text">Open in browser</string> + <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] --> + <string name="new_window_text">New Window</string> <!-- Accessibility text for the handle menu close button [CHAR LIMIT=NONE] --> <string name="close_text">Close</string> <!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] --> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt index 2493e9804907..6d63971b0b3e 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt @@ -46,7 +46,8 @@ enum class DesktopModeFlags( DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true), ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true), BACK_NAVIGATION(Flags::enableDesktopWindowingBackNavigation, true), - EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true); + EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true), + TASKBAR_RUNNING_APPS(Flags::enableDesktopWindowingTaskbarRunningApps, true); /** * Determines state of flag based on the actual flag and desktop mode developer option diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt index a6be64070ac1..4cd2fd04d3cf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt @@ -22,7 +22,6 @@ import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.os.UserHandle import android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI -import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.wm.shell.R import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL @@ -41,7 +40,6 @@ class MultiInstanceHelper @JvmOverloads constructor( /** * Returns whether a specific component desires to be launched in multiple instances. */ - @VisibleForTesting fun supportsMultiInstanceSplit(componentName: ComponentName?): Boolean { if (componentName == null || componentName.packageName == null) { // TODO(b/262864589): Handle empty component case @@ -60,7 +58,7 @@ class MultiInstanceHelper @JvmOverloads constructor( if (!supportsMultiInstanceProperty) { // If not checking the multi-instance properties, then return early - return false; + return false } // Check the activity property first diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java index 08de900f83ef..271c07d4011d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java @@ -19,6 +19,8 @@ package com.android.wm.shell.compatui; import static android.view.WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI; +import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.TaskInfo; @@ -38,7 +40,6 @@ import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState; import com.android.wm.shell.compatui.api.CompatUIEvent; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonAppeared; import com.android.wm.shell.shared.desktopmode.DesktopModeFlags; -import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import java.util.function.Consumer; @@ -82,7 +83,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { super(context, taskInfo, syncQueue, taskListener, displayLayout); mCallback = callback; mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat; - if (DesktopModeStatus.canEnterDesktopMode(context) + if (DESKTOP_WINDOWING_MODE.isEnabled(mContext) && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) { // Don't show the SCM button for freeform tasks mHasSizeCompat &= !taskInfo.isFreeform(); @@ -138,7 +139,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { boolean canShow) { final boolean prevHasSizeCompat = mHasSizeCompat; mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat; - if (DesktopModeStatus.canEnterDesktopMode(mContext) + if (DESKTOP_WINDOWING_MODE.isEnabled(mContext) && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)) { // Don't show the SCM button for freeform tasks mHasSizeCompat &= !taskInfo.isFreeform(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index da1af0d40a96..9cfbde4bad41 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -226,7 +226,8 @@ public abstract class WMShellModule { Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, @@ -246,7 +247,8 @@ public abstract class WMShellModule { desktopTasksController, rootTaskDisplayAreaOrganizer, interactionJankMonitor, - genericLinksParser); + genericLinksParser, + multiInstanceHelper); } return new CaptionWindowDecorViewModel( context, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 7175ec45c4ab..2bb172fc53ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -98,6 +98,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import com.android.wm.shell.windowdecor.extension.isFullscreen +import com.android.wm.shell.windowdecor.extension.isMultiWindow import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor @@ -902,6 +903,60 @@ class DesktopTasksController( request.triggerTask != null } + fun openNewWindow( + taskInfo: RunningTaskInfo + ) { + // TODO(b/337915660): Add a transition handler for these; animations + // need updates in some cases. + val newTaskWindowingMode = when { + taskInfo.isFreeform -> { + WINDOWING_MODE_FREEFORM + } + taskInfo.isFullscreen || taskInfo.isMultiWindow -> { + WINDOWING_MODE_MULTI_WINDOW + } + else -> { + error("Invalid windowing mode: ${taskInfo.windowingMode}") + } + } + + val baseActivity = taskInfo.baseActivity ?: return + val fillIn: Intent = context.packageManager + .getLaunchIntentForPackage( + baseActivity.packageName + ) ?: return + fillIn + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + val options = + ActivityOptions.makeBasic().apply { + launchWindowingMode = newTaskWindowingMode + isPendingIntentBackgroundActivityLaunchAllowedByPermission = true + pendingIntentBackgroundActivityStartMode = + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + } + val launchIntent = PendingIntent.getActivity( + context, + /* requestCode= */ 0, + fillIn, + PendingIntent.FLAG_IMMUTABLE + ) + when (newTaskWindowingMode) { + WINDOWING_MODE_MULTI_WINDOW -> { + val splitPosition = splitScreenController.determineNewInstancePosition(taskInfo) + splitScreenController.startIntent( + launchIntent, context.userId, fillIn, splitPosition, + options.toBundle(), null /* hideTaskToken */ + ) + } + WINDOWING_MODE_FREEFORM -> { + // TODO(b/336289597): This currently does not respect the desktop window limit. + val wct = WindowContainerTransaction() + wct.sendPendingIntent(launchIntent, fillIn, options.toBundle()) + transitions.startTransition(TRANSIT_OPEN, wct, null) + } + } + } + private fun handleFreeformTaskLaunch( task: RunningTaskInfo, transition: IBinder diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 54f908b395e7..da7e03f465e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -19,7 +19,6 @@ package com.android.wm.shell.recents; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.content.pm.PackageManager.FEATURE_PC; -import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS; import android.app.ActivityManager; @@ -365,7 +364,7 @@ public class RecentTasksController implements TaskStackListenerCallback, private boolean shouldEnableRunningTasksForDesktopMode() { return mPcFeatureEnabled || (DesktopModeStatus.canEnterDesktopMode(mContext) - && enableDesktopWindowingTaskbarRunningApps()); + && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext)); } @VisibleForTesting diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index b8575565ef8a..c4af14882a34 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import static android.view.Display.DEFAULT_DISPLAY; @@ -431,6 +432,20 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator.clearSplitPairedInRecents(reason); } + /** + * Determines which split position a new instance of a task should take. + * @param callingTask The task requesting a new instance. + * @return the split position of the new instance + */ + public int determineNewInstancePosition(@NonNull ActivityManager.RunningTaskInfo callingTask) { + if (callingTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + || getSplitPosition(callingTask.taskId) == SPLIT_POSITION_TOP_OR_LEFT) { + return SPLIT_POSITION_BOTTOM_OR_RIGHT; + } else { + return SPLIT_POSITION_TOP_OR_LEFT; + } + } + public void enterSplitScreen(int taskId, boolean leftOrTop) { enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index ecd5edae1662..633067d767dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -93,6 +93,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource; @@ -145,6 +146,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DesktopTasksController mDesktopTasksController; private final InputManager mInputManager; private final InteractionJankMonitor mInteractionJankMonitor; + private final MultiInstanceHelper mMultiInstanceHelper; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); @@ -204,7 +206,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor, - AppToWebGenericLinksParser genericLinksParser + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper ) { this( context, @@ -223,6 +226,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { transitions, desktopTasksController, genericLinksParser, + multiInstanceHelper, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, @@ -249,6 +253,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, @@ -268,6 +273,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSyncQueue = syncQueue; mTransitions = transitions; mDesktopTasksController = desktopTasksController.get(); + mMultiInstanceHelper = multiInstanceHelper; mShellCommandHandler = shellCommandHandler; mWindowManager = windowManager; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; @@ -536,6 +542,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.onOpenInBrowserClick(); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); + } else if (id == R.id.new_window_button) { + decoration.closeHandleMenu(); + mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } else if (id == R.id.maximize_window) { // TODO(b/346441962): move click detection logic into the decor's // {@link AppHeaderViewHolder}. Let it encapsulate the that and have it report @@ -1161,7 +1170,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mMainChoreographer, mSyncQueue, mRootTaskDisplayAreaOrganizer, - mGenericLinksParser); + mGenericLinksParser, + mMultiInstanceHelper); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final DragPositioningCallback dragPositioningCallback; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index df41d315fe5f..b8883443e5ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -74,6 +74,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; @@ -157,6 +158,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // to cancel the close. private final Runnable mCloseMaximizeWindowRunnable = this::closeMaximizeMenu; private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired; + private final MultiInstanceHelper mMultiInstanceHelper; DesktopModeWindowDecoration( Context context, @@ -171,13 +173,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Choreographer choreographer, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { this (context, userContext, displayController, splitScreenController, taskOrganizer, taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue, rootTaskDisplayAreaOrganizer, genericLinksParser, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new SurfaceControlViewHostFactory() {}, - DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE); + DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE, + multiInstanceHelper); } DesktopModeWindowDecoration( @@ -200,7 +204,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Supplier<SurfaceControl> surfaceControlSupplier, SurfaceControlViewHostFactory surfaceControlViewHostFactory, MaximizeMenuFactory maximizeMenuFactory, - HandleMenuFactory handleMenuFactory) { + HandleMenuFactory handleMenuFactory, + MultiInstanceHelper multiInstanceHelper) { super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, @@ -214,6 +219,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mGenericLinksParser = genericLinksParser; mMaximizeMenuFactory = maximizeMenuFactory; mHandleMenuFactory = handleMenuFactory; + mMultiInstanceHelper = multiInstanceHelper; } /** @@ -966,6 +972,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDisplayController, splitScreenController, DesktopModeStatus.canEnterDesktopMode(mContext), + Flags.enableDesktopWindowingMultiInstanceFeatures() + && mMultiInstanceHelper + .supportsMultiInstanceSplit(mTaskInfo.baseActivity), getBrowserLink(), mResult.mCaptionWidth, mResult.mCaptionHeight, @@ -1274,7 +1283,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Choreographer choreographer, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { return new DesktopModeWindowDecoration( context, userContext, @@ -1288,7 +1298,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin choreographer, syncQueue, rootTaskDisplayAreaOrganizer, - genericLinksParser); + genericLinksParser, + multiInstanceHelper); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 7a81d4c00c5e..74a640766dd0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -70,6 +70,7 @@ class HandleMenu( private val displayController: DisplayController, private val splitScreenController: SplitScreenController, private val shouldShowWindowingPill: Boolean, + private val shouldShowNewWindowButton: Boolean, val openInBrowserLink: Uri?, private val captionWidth: Int, private val captionHeight: Int, @@ -245,13 +246,24 @@ class HandleMenu( * Set up interactive elements & height of handle menu's more actions pill */ private fun setupMoreActionsPill(handleMenu: View, style: MenuStyle) { - val pill = handleMenu.requireViewById<View>(R.id.more_actions_pill).apply { - isGone = !SHOULD_SHOW_MORE_ACTIONS_PILL - background.colorFilter = BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) - } - pill.requireViewById<Button>(R.id.screenshot_button).let { screenshotBtn -> - screenshotBtn.setTextColor(style.textColor) - screenshotBtn.compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + val moreActionsPill = handleMenu.findViewById<View>(R.id.more_actions_pill) + moreActionsPill.isGone = !shouldShowNewWindowButton && !SHOULD_SHOW_SCREENSHOT_BUTTON + if (!moreActionsPill.isGone) { + handleMenu.requireViewById<Button>(R.id.screenshot_button).apply { + isGone = !SHOULD_SHOW_SCREENSHOT_BUTTON + background.colorFilter = + BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + setTextColor(style.textColor) + compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + } + handleMenu.findViewById<Button>(R.id.new_window_button).apply { + isGone = !shouldShowNewWindowButton + background.colorFilter = + BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + setTextColor(style.textColor) + compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + if (!isGone) setOnClickListener(onClickListener) + } } } @@ -439,9 +451,17 @@ class HandleMenu( R.dimen.desktop_mode_handle_menu_windowing_pill_height) menuHeight -= pillTopMargin } - if (!SHOULD_SHOW_MORE_ACTIONS_PILL) { + if (!SHOULD_SHOW_SCREENSHOT_BUTTON) { menuHeight -= loadDimensionPixelSize( - R.dimen.desktop_mode_handle_menu_more_actions_pill_height) + R.dimen.desktop_mode_handle_menu_screenshot_height + ) + } + if (!shouldShowNewWindowButton) { + menuHeight -= loadDimensionPixelSize( + R.dimen.desktop_mode_handle_menu_new_window_height + ) + } + if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton) { menuHeight -= pillTopMargin } if (!shouldShowBrowserPill) { @@ -501,7 +521,7 @@ class HandleMenu( companion object { private const val TAG = "HandleMenu" - private const val SHOULD_SHOW_MORE_ACTIONS_PILL = false + private const val SHOULD_SHOW_SCREENSHOT_BUTTON = false } } @@ -517,6 +537,7 @@ interface HandleMenuFactory { displayController: DisplayController, splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, + shouldShowNewWindowButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -536,6 +557,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { displayController: DisplayController, splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, + shouldShowNewWindowButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -551,6 +573,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { displayController, splitScreenController, shouldShowWindowingPill, + shouldShowNewWindowButton, openInBrowserLink, captionWidth, captionHeight, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index e26416047c56..c3a0bd94d7c0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -68,6 +68,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayInsetsController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.desktopmode.DesktopTasksController @@ -145,6 +146,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser private val bgExecutor = TestShellExecutor() + @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper private val transactionFactory = Supplier<SurfaceControl.Transaction> { SurfaceControl.Transaction() @@ -176,6 +178,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockTransitions, Optional.of(mockDesktopTasksController), mockGenericLinksParser, + mockMultiInstanceHelper, mockDesktopModeWindowDecorFactory, mockInputMonitorFactory, transactionFactory, @@ -659,8 +662,9 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration { val decoration = mock(DesktopModeWindowDecoration::class.java) whenever( - mockDesktopModeWindowDecorFactory.create(any(), any(), any(), any(), any(), eq(task), - any(), any(), any(), any(), any(), any(), any()) + mockDesktopModeWindowDecorFactory.create( + any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), + any(), any(), any()) ).thenReturn(decoration) decoration.mTaskInfo = task whenever(decoration.isFocused).thenReturn(task.isFocused) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 04b1eed02950..e60eb77ff16f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -89,6 +89,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -174,6 +175,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private HandleMenu mMockHandleMenu; @Mock private HandleMenuFactory mMockHandleMenuFactory; + private MultiInstanceHelper mMockMultiInstanceHelper; @Captor private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener; @Captor @@ -218,7 +220,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY); doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt()); doReturn(mMockHandleMenu).when(mMockHandleMenuFactory).create(any(), anyInt(), any(), any(), - any(), any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()); + any(), any(), any(), any(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), + anyInt()); } @After @@ -775,7 +778,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private void verifyHandleMenuCreated(@Nullable Uri uri) { verify(mMockHandleMenuFactory).create(any(), anyInt(), any(), any(), any(), any(), any(), - any(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt()); + any(), anyBoolean(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt()); } private void createMaximizeMenu(DesktopModeWindowDecoration decoration, MaximizeMenu menu) { @@ -831,7 +834,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer, mMockGenericLinksParser, SurfaceControl.Builder::new, mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, - mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory); + mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory, + mMockMultiInstanceHelper); windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener); windowDecor.setExclusionRegionListener(mMockExclusionRegionListener); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt index ed43aa3f1301..cca83dd031f7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt @@ -227,11 +227,11 @@ class HandleMenuTest : ShellTestCase() { else -> error("Invalid windowing mode") } val handleMenu = HandleMenu(mockDesktopWindowDecoration, layoutId, - onClickListener, onTouchListener, appIcon, appName, displayController, - splitScreenController, shouldShowWindowingPill = true, - null /* openInBrowserLink */, captionWidth = HANDLE_WIDTH, captionHeight = 50, - captionX = captionX - ) + onClickListener, onTouchListener, appIcon, appName, displayController, + splitScreenController, shouldShowWindowingPill = true, + shouldShowNewWindowButton = true, + openInBrowserLink = null, captionWidth = HANDLE_WIDTH, captionHeight = 50, + captionX = captionX) handleMenu.show() return handleMenu } diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/EdgeToEdgeUtils.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/EdgeToEdgeUtils.java index 6e53012e1245..062e9b8ed032 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/EdgeToEdgeUtils.java +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/EdgeToEdgeUtils.java @@ -36,7 +36,7 @@ public class EdgeToEdgeUtils { * Enable Edge to Edge and handle overlaps using insets. It should be called before * setContentView. */ - static void enable(@NonNull ComponentActivity activity) { + public static void enable(@NonNull ComponentActivity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { return; } diff --git a/packages/SystemUI/aconfig/biometrics_framework.aconfig b/packages/SystemUI/aconfig/biometrics_framework.aconfig index bd1a442b874f..e81d5d5ece5a 100644 --- a/packages/SystemUI/aconfig/biometrics_framework.aconfig +++ b/packages/SystemUI/aconfig/biometrics_framework.aconfig @@ -4,13 +4,6 @@ container: "system" # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors. flag { - name: "bp_talkback" - namespace: "biometrics_framework" - description: "Adds talkback directional guidance when using UDFPS with biometric prompt" - bug: "310044658" -} - -flag { name: "constraint_bp" namespace: "biometrics_framework" description: "Refactors Biometric Prompt to use a ConstraintLayout" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 34fbcacea683..40fb7691c0c2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -60,7 +60,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; import com.android.systemui.scene.FakeWindowRootViewComponent; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shade.ui.viewmodel.NotificationShadeWindowModel; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.DozeParameters; @@ -107,7 +106,6 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Mock private ShadeWindowLogger mShadeWindowLogger; @Mock private SelectedUserInteractor mSelectedUserInteractor; @Mock private UserTracker mUserTracker; - @Mock private NotificationShadeWindowModel mNotificationShadeWindowModel; @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener; @@ -163,7 +161,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { mShadeWindowLogger, () -> mSelectedUserInteractor, mUserTracker, - mNotificationShadeWindowModel, + mKosmos.getNotificationShadeWindowModel(), mKosmos::getCommunalInteractor) { @Override protected boolean isDebuggable() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 0352da30f531..9521be1f11a7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -412,7 +412,6 @@ public class AuthContainerView extends LinearLayout }); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - setFocusableInTouchMode(true); requestFocus(); } @@ -464,7 +463,8 @@ public class AuthContainerView extends LinearLayout } } - private void onBackInvoked() { + @VisibleForTesting + public void onBackInvoked() { sendEarlyUserCanceled(); animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index b1cba2fb3ab8..874ad9ec199c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -36,7 +36,6 @@ import android.util.RotationUtils import android.view.HapticFeedbackConstants import android.view.MotionEvent import com.android.launcher3.icons.IconProvider -import com.android.systemui.Flags.bpTalkback import com.android.systemui.Flags.constraintBp import com.android.systemui.biometrics.UdfpsUtils import com.android.systemui.biometrics.Utils @@ -916,10 +915,9 @@ constructor( touchExplorationEnabled: Boolean, ): Boolean { if ( - bpTalkback() && - modalities.first().hasUdfps && - touchExplorationEnabled && - !isAuthenticated.first().isAuthenticated + modalities.first().hasUdfps && + touchExplorationEnabled && + !isAuthenticated.first().isAuthenticated ) { // TODO(b/315184924): Remove uses of UdfpsUtils val scaledTouch = diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 6ed84e573d7c..89fce4a70c6c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -293,11 +293,11 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi if (shouldUseFloatBrightness()) { mDozeService.setDozeScreenBrightnessFloat( clampToDimBrightnessForScreenOffFloat( - clampToUserSettingFloat(mDefaultDozeBrightnessFloat))); + clampToUserSettingOrAutoBrightnessFloat(mDefaultDozeBrightnessFloat))); } else { mDozeService.setDozeScreenBrightness( clampToDimBrightnessForScreenOff( - clampToUserSetting(mDefaultDozeBrightness))); + clampToUserSettingOrAutoBrightness(mDefaultDozeBrightness))); } mDozeHost.setAodDimmingScrim(0f); } @@ -310,10 +310,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi return brightness; } - int userSetting = mSystemSettings.getIntForUser( - Settings.System.SCREEN_BRIGHTNESS, Integer.MAX_VALUE, - UserHandle.USER_CURRENT); - return Math.min(brightness, userSetting); + return Math.min(brightness, getScreenBrightness()); } @SuppressLint("AndroidFrameworkRequiresPermission") @@ -325,8 +322,33 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi return brightness; } - float userSetting = mDisplayManager.getBrightness(Display.DEFAULT_DISPLAY); - return Math.min(brightness, userSetting); + return Math.min(brightness, getScreenBrightnessFloat()); + } + + private int clampToUserSettingOrAutoBrightness(int brightness) { + return Math.min(brightness, getScreenBrightness()); + } + + private float clampToUserSettingOrAutoBrightnessFloat(float brightness) { + return Math.min(brightness, getScreenBrightnessFloat()); + } + + /** + * Gets the current screen brightness that may have been set by manually by the user + * or by autobrightness. + */ + private int getScreenBrightness() { + return mSystemSettings.getIntForUser( + Settings.System.SCREEN_BRIGHTNESS, Integer.MAX_VALUE, + UserHandle.USER_CURRENT); + } + + /** + * Gets the current screen brightness that may have been set by manually by the user + * or by autobrightness. + */ + private float getScreenBrightnessFloat() { + return mDisplayManager.getBrightness(Display.DEFAULT_DISPLAY); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt index 29450a20b1d3..3fe3162cf17d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt @@ -26,7 +26,7 @@ import com.android.systemui.screenshot.data.repository.ProfileTypeRepository import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask -import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.shared.desktopmode.DesktopModeFlags import javax.inject.Inject import kotlinx.coroutines.flow.first @@ -48,7 +48,7 @@ constructor( return NotMatched(policy = NAME, reason = SHADE_EXPANDED) } - if (DesktopModeStatus.canEnterDesktopMode(context)) { + if (DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context)) { content.rootTasks.firstOrNull()?.also { if (it.windowingMode == WINDOWING_MODE_FREEFORM) { return NotMatched(policy = NAME, reason = DESKTOP_MODE_ENABLED) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 1e3ee280204b..dc69cdadc320 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -35,7 +35,6 @@ import android.os.UserManager import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import android.testing.ViewUtils -import android.view.KeyEvent import android.view.View import android.view.WindowInsets import android.view.WindowManager @@ -202,8 +201,7 @@ open class AuthContainerViewTest : SysuiTestCase() { val root = container.rootView // Simulate back invocation - container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)) - container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)) + container.onBackInvoked() waitForIdleSync() assertThat(container.parent).isNull() @@ -217,8 +215,7 @@ open class AuthContainerViewTest : SysuiTestCase() { val root = container.rootView // Simulate back invocation - container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)) - container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)) + container.onBackInvoked() waitForIdleSync() assertThat(container.parent).isNull() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index e603db417785..b8b93c9c6f7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -44,7 +44,6 @@ import android.view.MotionEvent import android.view.Surface import androidx.test.filters.SmallTest import com.android.app.activityTaskManager -import com.android.systemui.Flags.FLAG_BP_TALKBACK import com.android.systemui.Flags.FLAG_CONSTRAINT_BP import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController @@ -1356,7 +1355,6 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - @EnableFlags(FLAG_BP_TALKBACK) fun hint_for_talkback_guidance() = runGenericTest { val hint by collectLastValue(kosmos.promptViewModel.accessibilityHint) @@ -1379,7 +1377,6 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - @EnableFlags(FLAG_BP_TALKBACK) fun no_hint_for_talkback_guidance_after_auth() = runGenericTest { val hint by collectLastValue(kosmos.promptViewModel.accessibilityHint) diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 4818119045a5..86da2037d97a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -58,7 +58,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.feature.flags.Flags; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.policy.DevicePostureController; @@ -105,8 +104,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Mock DozeParameters mDozeParameters; @Mock - DockManager mDockManager; - @Mock DevicePostureController mDevicePostureController; @Mock DozeLog mDozeLog; @@ -114,8 +111,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { SystemSettings mSystemSettings; @Mock DisplayManager mDisplayManager; - private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); - private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); + private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + private final FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); private DozeScreenBrightness mScreen; @@ -249,32 +246,35 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test - @RequiresFlagsDisabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) - public void testAod_usesLightSensorNotClampingToAutoBrightnessValue_Int() { - int maxBrightness = 3; - when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(), - eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightness); + @RequiresFlagsEnabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) + public void initialBrightness_clampsToAutoBrightnessValue_Float() { + float maxBrightnessFromAutoBrightness = DEFAULT_BRIGHTNESS_FLOAT / 2; + when(mDisplayManager.getBrightness(Display.DEFAULT_DISPLAY)).thenReturn( + maxBrightnessFromAutoBrightness + ); when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), eq(UserHandle.USER_CURRENT))) .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - assertEquals(DEFAULT_BRIGHTNESS_INT, mServiceFake.screenBrightnessInt); - assertTrue(Float.isNaN(mServiceFake.screenBrightnessFloat)); + assertEquals(maxBrightnessFromAutoBrightness, mServiceFake.screenBrightnessFloat, + DELTA); + assertEquals(PowerManager.BRIGHTNESS_DEFAULT, mServiceFake.screenBrightnessInt); } @Test - @RequiresFlagsEnabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) - public void testAod_usesLightSensorNotClampingToAutoBrightnessValue_Float() { - float maxBrightness = DEFAULT_BRIGHTNESS_FLOAT / 2; - when(mDisplayManager.getBrightness(Display.DEFAULT_DISPLAY)).thenReturn(maxBrightness); + @RequiresFlagsDisabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) + public void initialBrightness_clampsToAutoBrightnessValue_Int() { + int maxBrightnessFromAutoBrightness = DEFAULT_BRIGHTNESS_INT / 2; + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(), + eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightnessFromAutoBrightness); when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), eq(UserHandle.USER_CURRENT))) .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - assertEquals(DEFAULT_BRIGHTNESS_FLOAT, mServiceFake.screenBrightnessFloat, DELTA); - assertEquals(PowerManager.BRIGHTNESS_DEFAULT, mServiceFake.screenBrightnessInt); + assertEquals(maxBrightnessFromAutoBrightness, mServiceFake.screenBrightnessInt); + assertTrue(Float.isNaN(mServiceFake.screenBrightnessFloat)); } @Test @@ -378,6 +378,54 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test + @RequiresFlagsEnabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) + public void lightSensorChangesInAod_doesNotClampToAutoBrightnessValue_Float() { + // GIVEN auto brightness reports low brightness + float maxBrightnessFromAutoBrightness = DEFAULT_BRIGHTNESS_FLOAT / 2; + when(mDisplayManager.getBrightness(Display.DEFAULT_DISPLAY)) + .thenReturn(maxBrightnessFromAutoBrightness); + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))) + .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + + // GIVEN the device is DOZE_AOD and the display state changes to ON + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new sensor event sent + mSensor.sendSensorEvent(3); + + // THEN brightness is updated + assertEquals(SENSOR_TO_BRIGHTNESS_FLOAT[3], mServiceFake.screenBrightnessFloat, DELTA); + assertEquals(PowerManager.BRIGHTNESS_DEFAULT, mServiceFake.screenBrightnessInt); + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) + public void lightSensorChangesInAod_doesNotClampToAutoBrightnessValue_Int() { + // GIVEN auto brightness reports low brightness + int maxBrightnessFromAutoBrightness = 1; + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS), anyInt(), + eq(UserHandle.USER_CURRENT))).thenReturn(maxBrightnessFromAutoBrightness); + when(mSystemSettings.getIntForUser(eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))) + .thenReturn(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + + // GIVEN the device is DOZE_AOD and the display state changes to ON + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new sensor event sent + mSensor.sendSensorEvent(3); + + // THEN brightness is updated + assertEquals(SENSOR_TO_BRIGHTNESS_INT[3], mServiceFake.screenBrightnessInt); + assertTrue(Float.isNaN(mServiceFake.screenBrightnessFloat)); + } + + @Test @RequiresFlagsDisabled(Flags.FLAG_DOZE_BRIGHTNESS_FLOAT) public void docked_usesLightSensor_Int() { // GIVEN the device is docked and the display state changes to ON diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index ff6588758066..e3a38a8d6763 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -111,7 +111,6 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.ShadeWindowLogger; import com.android.systemui.shade.domain.interactor.ShadeInteractor; -import com.android.systemui.shade.ui.viewmodel.NotificationShadeWindowModel; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -226,7 +225,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock DreamViewModel mDreamViewModel; private @Mock CommunalTransitionViewModel mCommunalTransitionViewModel; private @Mock SystemPropertiesHelper mSystemPropertiesHelper; - @Mock private NotificationShadeWindowModel mNotificationShadeWindowModel; private FakeFeatureFlags mFeatureFlags; private final int mDefaultUserId = 100; @@ -274,7 +272,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mShadeWindowLogger, () -> mSelectedUserInteractor, mUserTracker, - mNotificationShadeWindowModel, + mKosmos.getNotificationShadeWindowModel(), mKosmos::getCommunalInteractor); mFeatureFlags = new FakeFeatureFlags(); mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt index 191a048f5f3f..a5fbfb539354 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt @@ -18,13 +18,11 @@ package com.android.systemui.screenshot.policy import android.content.ComponentName import android.content.Context -import android.content.res.Resources import android.os.UserHandle import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.internal.R import com.android.systemui.kosmos.Kosmos import com.android.systemui.screenshot.data.model.DisplayContentModel import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES @@ -49,7 +47,6 @@ import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.DESKTO import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.SHADE_EXPANDED import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.WORK_TASK_IS_TOP import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.WORK_TASK_NOT_TOP -import com.android.systemui.util.mockito.whenever import com.android.window.flags.Flags import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest @@ -58,7 +55,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.MockitoAnnotations import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule @@ -70,19 +66,12 @@ class WorkProfilePolicyTest { @JvmField @Rule(order = 2) val mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock lateinit var mContext: Context - @Mock lateinit var mResources: Resources private val kosmos = Kosmos() private lateinit var policy: WorkProfilePolicy @Before fun setUp() { - MockitoAnnotations.initMocks(this) - - // Set desktop mode supported - whenever(mContext.resources).thenReturn(mResources) - whenever(mResources.getBoolean(R.bool.config_isDesktopModeSupported)).thenReturn(true) - policy = WorkProfilePolicy(kosmos.profileTypeRepository, mContext) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 7f964d159999..e5e04dc9b82f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -349,10 +349,10 @@ public class BubblesTest extends SysuiTestCase { private Display mDefaultDisplay; @Mock private Lazy<ViewCapture> mLazyViewCapture; - @Mock private NotificationShadeWindowModel mNotificationShadeWindowModel; private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this); private ShadeInteractor mShadeInteractor; + private NotificationShadeWindowModel mNotificationShadeWindowModel; private ShellTaskOrganizer mShellTaskOrganizer; private TaskViewTransitions mTaskViewTransitions; @@ -411,6 +411,7 @@ public class BubblesTest extends SysuiTestCase { when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false)); mShadeInteractor = mKosmos.getShadeInteractor(); + mNotificationShadeWindowModel = mKosmos.getNotificationShadeWindowModel(); mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl( mContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 8614fc905934..e6bd24b6b99a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -59,6 +59,7 @@ import com.android.systemui.settings.brightness.domain.interactor.brightnessMirr import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shadeController +import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor @@ -140,6 +141,7 @@ class KosmosJavaAdapter() { val shadeController by lazy { kosmos.shadeController } val shadeRepository by lazy { kosmos.shadeRepository } val shadeInteractor by lazy { kosmos.shadeInteractor } + val notificationShadeWindowModel by lazy { kosmos.notificationShadeWindowModel } val wifiInteractor by lazy { kosmos.wifiInteractor } val fakeWifiRepository by lazy { kosmos.fakeWifiRepository } val volumeDialogInteractor by lazy { kosmos.volumeDialogInteractor } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 03fbfd37cbdb..f936b8174c28 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -620,6 +620,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub private void setPowerStatsThrottlePeriods(BatteryStatsImpl.BatteryStatsConfig.Builder builder, String configString) { + if (configString == null) { + return; + } + Matcher matcher = Pattern.compile("([^:]+):(\\d+)\\s*").matcher(configString); while (matcher.find()) { String powerComponentName = matcher.group(1); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index ef7abdd4645c..6cce722843b5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -227,6 +227,9 @@ public class FaceAuthenticationClient onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); mCallback.onClientFinished(this, false /* success */); } + } else { + Slog.e(TAG, "Cancellation signal is null"); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index d04afdb72913..dee4b4fd18c7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -359,7 +359,8 @@ public class FingerprintAuthenticationClient mCallback.onClientFinished(this, false /* success */); } } else { - Slog.e(TAG, "cancellation signal was null"); + Slog.e(TAG, "Cancellation signal was null"); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java index 12c3197aba2a..59fffe7ee393 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java @@ -347,7 +347,7 @@ public class BrightnessClamperController { data.mDisplayDeviceConfig)); } if (flags.useNewHdrBrightnessModifier()) { - modifiers.add(new HdrBrightnessModifier(handler, listener, data)); + modifiers.add(new HdrBrightnessModifier(handler, context, listener, data)); } return modifiers; } diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java b/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java index ae1801ccea74..4ab4336122d0 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java +++ b/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java @@ -21,10 +21,15 @@ import static com.android.server.display.brightness.clamper.LightSensorControlle import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.content.Context; +import android.database.ContentObserver; import android.hardware.display.DisplayManagerInternal; +import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; import android.view.SurfaceControlHdrLayerInfoListener; import com.android.internal.annotations.VisibleForTesting; @@ -44,6 +49,11 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, static final float DEFAULT_MAX_HDR_SDR_RATIO = 1.0f; private static final float DEFAULT_HDR_LAYER_SIZE = -1.0f; + private final Uri mLowPowerModeSetting = Settings.Global.getUriFor( + Settings.Global.LOW_POWER_MODE); + + private final ContentObserver mContentObserver; + private final SurfaceControlHdrLayerInfoListener mHdrListener = new SurfaceControlHdrLayerInfoListener() { @Override @@ -52,7 +62,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, boolean hdrLayerPresent = numberOfHdrLayers > 0; mHandler.post(() -> HdrBrightnessModifier.this.onHdrInfoChanged( hdrLayerPresent ? (float) (maxW * maxH) : DEFAULT_HDR_LAYER_SIZE, - hdrLayerPresent ? maxDesiredHdrSdrRatio : DEFAULT_MAX_HDR_SDR_RATIO)); + hdrLayerPresent ? Math.max(maxDesiredHdrSdrRatio, + DEFAULT_MAX_HDR_SDR_RATIO) : DEFAULT_MAX_HDR_SDR_RATIO)); } }; @@ -62,6 +73,7 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private final Runnable mDebouncer; private IBinder mRegisteredDisplayToken; + private boolean mContentObserverRegistered = false; private DisplayDeviceConfig mDisplayDeviceConfig; @Nullable @@ -73,6 +85,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mAmbientLux = INVALID_LUX; + private boolean mLowPowerMode = false; + private Mode mMode = Mode.NO_HDR; // The maximum brightness allowed for current lux private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; @@ -81,17 +95,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; private float mPendingTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; - HdrBrightnessModifier(Handler handler, + HdrBrightnessModifier(Handler handler, Context context, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData displayData) { - this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(), displayData); + this(new Handler(handler.getLooper()), clamperChangeListener, + new Injector(context), displayData); } @VisibleForTesting HdrBrightnessModifier(Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, - Injector injector, - BrightnessClamperController.DisplayDeviceData displayData) { + Injector injector, BrightnessClamperController.DisplayDeviceData displayData) { mHandler = handler; mClamperChangeListener = clamperChangeListener; mInjector = injector; @@ -100,6 +114,12 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, mMaxBrightness = mPendingMaxBrightness; mClamperChangeListener.onChanged(); }; + mContentObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + onLowPowerModeChange(); + } + }; mHandler.post(() -> onDisplayChanged(displayData)); } @@ -135,12 +155,14 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, pw.println(" mMaxDesiredHdrRatio=" + mMaxDesiredHdrRatio); pw.println(" mHdrLayerSize=" + mHdrLayerSize); pw.println(" mAmbientLux=" + mAmbientLux); + pw.println(" mLowPowerMode=" + mLowPowerMode); pw.println(" mMode=" + mMode); pw.println(" mMaxBrightness=" + mMaxBrightness); pw.println(" mPendingMaxBrightness=" + mPendingMaxBrightness); pw.println(" mTransitionRate=" + mTransitionRate); pw.println(" mPendingTransitionRate=" + mPendingTransitionRate); pw.println(" mHdrListener registered=" + (mRegisteredDisplayToken != null)); + pw.println(" mContentObserverRegistered=" + mContentObserverRegistered); } // Called in DisplayControllerHandler @@ -182,7 +204,25 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } else { registerHdrListener(displayData.mDisplayToken); } - recalculate(data, mMaxDesiredHdrRatio); + if (data == null || data.allowInLowPowerMode) { + unregisterContentObserver(); + } else { + registerContentObserver(); + } + + Mode newMode = recalculateMode(data); + // mode changed, or mode was HDR and HdrBrightnessData changed + boolean needToNotifyChange = mMode != newMode + || (mMode != HdrBrightnessModifier.Mode.NO_HDR && data != mHdrBrightnessData); + mMode = newMode; + mHdrBrightnessData = data; + mMaxBrightness = findBrightnessLimit(mHdrBrightnessData, mAmbientLux); + + if (needToNotifyChange) { + // data changed, reset custom transition rate + mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; + mClamperChangeListener.onChanged(); + } } // Called in DisplayControllerHandler, when any modifier state changes @@ -226,30 +266,6 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } // Called in DisplayControllerHandler - private void recalculate(@Nullable HdrBrightnessData data, float maxDesiredHdrRatio) { - Mode newMode = recalculateMode(data); - // if HDR mode changed, notify changed - boolean needToNotifyChange = mMode != newMode; - // If HDR mode is active, we need to check if other HDR params are changed - if (mMode != HdrBrightnessModifier.Mode.NO_HDR) { - if (!BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrRatio) - || data != mHdrBrightnessData) { - needToNotifyChange = true; - } - } - - mMode = newMode; - mHdrBrightnessData = data; - mMaxDesiredHdrRatio = maxDesiredHdrRatio; - - if (needToNotifyChange) { - // data or hdr layer changed, reset custom transition rate - mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; - mClamperChangeListener.onChanged(); - } - } - - // Called in DisplayControllerHandler private Mode recalculateMode(@Nullable HdrBrightnessData data) { // no config if (data == null) { @@ -259,6 +275,10 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, if (mHdrLayerSize == DEFAULT_HDR_LAYER_SIZE) { return Mode.NO_HDR; } + // low power mode and not allowed in low power mode + if (!data.allowInLowPowerMode && mLowPowerMode) { + return Mode.NO_HDR; + } // HDR layer < minHdr % for Nbm if (mHdrLayerSize < mScreenSize * data.minimumHdrPercentOfScreenForNbm) { return Mode.NO_HDR; @@ -271,6 +291,16 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, return Mode.HBM_HDR; } + private void onLowPowerModeChange() { + mLowPowerMode = mInjector.isLowPowerMode(); + Mode newMode = recalculateMode(mHdrBrightnessData); + if (newMode != mMode) { + mMode = newMode; + mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; + mClamperChangeListener.onChanged(); + } + } + private float getMaxBrightness(Mode mode, float maxBrightness, HdrBrightnessData data) { if (mode == Mode.NBM_HDR) { return Math.min(data.hbmTransitionPoint, maxBrightness); @@ -282,7 +312,13 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } // Called in DisplayControllerHandler - private float findBrightnessLimit(HdrBrightnessData data, float ambientLux) { + private float findBrightnessLimit(@Nullable HdrBrightnessData data, float ambientLux) { + if (data == null) { + return PowerManager.BRIGHTNESS_MAX; + } + if (ambientLux == INVALID_LUX) { + return PowerManager.BRIGHTNESS_MAX; + } float foundAmbientBoundary = Float.MAX_VALUE; float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; for (Map.Entry<Float, Float> brightnessPoint : @@ -300,7 +336,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, // Called in DisplayControllerHandler private void onHdrInfoChanged(float hdrLayerSize, float maxDesiredHdrSdrRatio) { mHdrLayerSize = hdrLayerSize; - recalculate(mHdrBrightnessData, maxDesiredHdrSdrRatio); + Mode newMode = recalculateMode(mHdrBrightnessData); + // mode changed, or mode was HDR and maxDesiredHdrRatio changed + boolean needToNotifyChange = mMode != newMode + || (mMode != HdrBrightnessModifier.Mode.NO_HDR + && !BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrSdrRatio)); + mMode = newMode; + mMaxDesiredHdrRatio = maxDesiredHdrSdrRatio; + if (needToNotifyChange) { + mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; + mClamperChangeListener.onChanged(); + } } // Called in DisplayControllerHandler @@ -324,12 +370,36 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } } + // Called in DisplayControllerHandler + private void registerContentObserver() { + if (!mContentObserverRegistered) { + mInjector.registerContentObserver(mContentObserver, mLowPowerModeSetting); + mContentObserverRegistered = true; + mLowPowerMode = mInjector.isLowPowerMode(); + } + } + + // Called in DisplayControllerHandler + private void unregisterContentObserver() { + if (mContentObserverRegistered) { + mInjector.unregisterContentObserver(mContentObserver); + mContentObserverRegistered = false; + mLowPowerMode = false; + } + } + private enum Mode { NO_HDR, NBM_HDR, HBM_HDR } @SuppressLint("MissingPermission") static class Injector { + private final Context mContext; + + Injector(Context context) { + mContext = context; + } + void registerHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.register(token); } @@ -337,5 +407,19 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, void unregisterHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.unregister(token); } + + void registerContentObserver(ContentObserver observer, Uri uri) { + mContext.getContentResolver().registerContentObserver(uri, false, + observer, UserHandle.USER_ALL); + } + + void unregisterContentObserver(ContentObserver observer) { + mContext.getContentResolver().unregisterContentObserver(observer); + } + + boolean isLowPowerMode() { + return Settings.Global.getInt( + mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) != 0; + } } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 730077c854fb..61d8e0be4950 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -619,7 +619,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. case Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD: { if (!mNewInputMethodSwitcherMenuEnabled) { if (userId == mCurrentUserId) { - mMenuController.updateKeyboardFromSettingsLocked(); + mMenuController.updateKeyboardFromSettingsLocked(userId); } } break; @@ -693,7 +693,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. senderUserId); } } else { - mMenuController.hideInputMethodMenu(); + mMenuController.hideInputMethodMenu(senderUserId); } } else { Slog.w(TAG, "Unexpected intent " + intent); @@ -1222,12 +1222,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. } } - @GuardedBy("ImfLock.class") - @UserIdInt - int getCurrentImeUserIdLocked() { - return mCurrentUserId; - } - private final class InkWindowInitializer implements Runnable { public void run() { synchronized (ImfLock.class) { @@ -1239,12 +1233,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. } } - private void onUpdateEditorToolType(int toolType) { - synchronized (ImfLock.class) { - IInputMethodInvoker curMethod = getCurMethodLocked(); - if (curMethod != null) { - curMethod.updateEditorToolType(toolType); - } + @GuardedBy("ImfLock.class") + private void onUpdateEditorToolTypeLocked(@MotionEvent.ToolType int toolType) { + final IInputMethodInvoker curMethod = getCurMethodLocked(); + if (curMethod != null) { + curMethod.updateEditorToolType(toolType); } } @@ -1826,7 +1819,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (mNewInputMethodSwitcherMenuEnabled) { mMenuControllerNew.hide(bindingController.getCurTokenDisplayId(), userId); } else { - mMenuController.hideInputMethodMenuLocked(); + mMenuController.hideInputMethodMenuLocked(userId); } } } @@ -2860,7 +2853,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. void updateFromSettingsLocked(boolean enabledMayChange, @UserIdInt int userId) { updateInputMethodsFromSettingsLocked(enabledMayChange, userId); if (!mNewInputMethodSwitcherMenuEnabled) { - mMenuController.updateKeyboardFromSettingsLocked(); + mMenuController.updateKeyboardFromSettingsLocked(userId); } } @@ -3465,7 +3458,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (Flags.useHandwritingListenerForTooltype()) { maybeReportToolType(); } else if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) { - onUpdateEditorToolType(lastClickToolType); + onUpdateEditorToolTypeLocked(lastClickToolType); } mVisibilityApplier.performShowIme(windowToken, statsToken, mVisibilityStateComputer.getShowFlagsForInputMethodServiceOnly(), @@ -3499,7 +3492,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // other toolTypes are irrelevant and reported as unknown. toolType = MotionEvent.TOOL_TYPE_UNKNOWN; } - onUpdateEditorToolType(toolType); + onUpdateEditorToolTypeLocked(toolType); } @Override @@ -5071,7 +5064,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mMenuControllerNew.show(menuItems, selectedIndex, displayId, userId); } else { mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId, - lastInputMethodId, lastInputMethodSubtypeId, imList); + lastInputMethodId, lastInputMethodSubtypeId, imList, userId); } } @@ -5948,7 +5941,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. final var bindingController = getInputMethodBindingController(userId); mMenuControllerNew.hide(bindingController.getCurTokenDisplayId(), userId); } else { - mMenuController.hideInputMethodMenuLocked(); + mMenuController.hideInputMethodMenuLocked(userId); } } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java index ba5c13e75c15..f16a5a077d8b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java @@ -21,6 +21,7 @@ import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; @@ -77,13 +78,12 @@ final class InputMethodMenuController { @GuardedBy("ImfLock.class") void showInputMethodMenuLocked(boolean showAuxSubtypes, int displayId, String preferredInputMethodId, int preferredInputMethodSubtypeId, - @NonNull List<ImeSubtypeListItem> imList) { + @NonNull List<ImeSubtypeListItem> imList, @UserIdInt int userId) { if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes); - final int userId = mService.getCurrentImeUserIdLocked(); final var bindingController = mService.getInputMethodBindingController(userId); - hideInputMethodMenuLocked(); + hideInputMethodMenuLocked(userId); if (preferredInputMethodSubtypeId == NOT_A_SUBTYPE_ID) { final InputMethodSubtype currentSubtype = @@ -131,7 +131,7 @@ final class InputMethodMenuController { } final Context dialogWindowContext = mDialogWindowContext.get(displayId); mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); - mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); + mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu(userId)); final Context dialogContext = mDialogBuilder.getContext(); final TypedArray a = dialogContext.obtainStyledAttributes(null, @@ -162,7 +162,7 @@ final class InputMethodMenuController { isChecked, userId); // Ensure that the input method dialog is dismissed when changing // the hardware keyboard state. - hideInputMethodMenu(); + hideInputMethodMenu(userId); }); // Fill the list items with onClick listener, which takes care of IME (and subtype) @@ -185,7 +185,7 @@ final class InputMethodMenuController { } mService.setInputMethodLocked(im.getId(), subtypeId, userId); } - hideInputMethodMenuLocked(); + hideInputMethodMenuLocked(userId); } }; mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener); @@ -209,10 +209,10 @@ final class InputMethodMenuController { mSwitchingDialog.show(); } - void updateKeyboardFromSettingsLocked() { + void updateKeyboardFromSettingsLocked(@UserIdInt int userId) { mShowImeWithHardKeyboard = SecureSettingsWrapper.getBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, - false, mService.getCurrentImeUserIdLocked()); + false, userId); if (mSwitchingDialog != null && mSwitchingDialogTitleView != null && mSwitchingDialog.isShowing()) { final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById( @@ -223,18 +223,22 @@ final class InputMethodMenuController { /** * Hides the input method switcher menu. + * + * @param userId user ID for this operation */ - void hideInputMethodMenu() { + void hideInputMethodMenu(@UserIdInt int userId) { synchronized (ImfLock.class) { - hideInputMethodMenuLocked(); + hideInputMethodMenuLocked(userId); } } /** * Hides the input method switcher menu, synchronised version of {@link #hideInputMethodMenu}. + * + * @param userId user ID for this operation */ @GuardedBy("ImfLock.class") - void hideInputMethodMenuLocked() { + void hideInputMethodMenuLocked(@UserIdInt int userId) { if (DEBUG) Slog.v(TAG, "Hide switching menu"); if (mSwitchingDialog != null) { @@ -242,8 +246,6 @@ final class InputMethodMenuController { mSwitchingDialog = null; mSwitchingDialogTitleView = null; - // TODO(b/305849394): Make InputMethodMenuController multi-user aware - final int userId = mService.getCurrentImeUserIdLocked(); mService.updateSystemUiLocked(userId); mService.sendOnNavButtonFlagsChangedToAllImesLocked(); mDialogBuilder = null; diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt index 0ed96ae52491..bb025ccbdb33 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt @@ -16,7 +16,10 @@ package com.android.server.display.brightness.clamper +import android.content.Context +import android.database.ContentObserver import android.hardware.display.DisplayManagerInternal +import android.net.Uri import android.os.IBinder import android.os.PowerManager.BRIGHTNESS_MAX import android.util.Spline @@ -51,7 +54,7 @@ class HdrBrightnessModifierTest { private val stoppedClock = OffsettableClock.Stopped() private val testHandler = TestHandler(null, stoppedClock) - private val testInjector = TestInjector() + private val testInjector = TestInjector(mock<Context>()) private val mockChangeListener = mock<ClamperChangeListener>() private val mockDisplayDeviceConfig = mock<DisplayDeviceConfig>() private val mockDisplayBinder = mock<IBinder>() @@ -63,14 +66,14 @@ class HdrBrightnessModifierTest { private val dummyData = createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinder) @Test - fun `change listener is not called on init`() { + fun changeListenerIsNotCalledOnInit() { initHdrModifier() verify(mockChangeListener, never()).onChanged() } @Test - fun `hdr listener registered on init if hdr data is present`() { + fun hdrListenerRegisteredOnInit_hdrDataPresent() { initHdrModifier() assertThat(testInjector.registeredHdrListener).isNotNull() @@ -78,22 +81,19 @@ class HdrBrightnessModifierTest { } @Test - fun `hdr listener not registered on init if hdr data is missing`() { - initHdrModifier(null) - - testHandler.flush() + fun hdrListenerNotRegisteredOnInit_hdrDataMissing() { + initHdrModifier(hdrBrightnessData = null) assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() } @Test - fun `unsubscribes hdr listener when display changed with no hdr data`() { + fun unsubscribeHdrListener_displayChangedWithNoHdrData() { initHdrModifier() whenever(mockDisplayDeviceConfig.hdrBrightnessData).thenReturn(null) modifier.onDisplayChanged(dummyData) - testHandler.flush() assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() @@ -101,12 +101,11 @@ class HdrBrightnessModifierTest { } @Test - fun `resubscribes hdr listener when display changed with different token`() { + fun resubscribesHdrListener_displayChangedWithDifferentToken() { initHdrModifier() modifier.onDisplayChanged( createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinderOther)) - testHandler.flush() assertThat(testInjector.registeredHdrListener).isNotNull() assertThat(testInjector.registeredToken).isEqualTo(mockDisplayBinderOther) @@ -114,7 +113,28 @@ class HdrBrightnessModifierTest { } @Test - fun `test NO_HDR mode`() { + fun contentObserverNotRegisteredOnInit_hdrDataMissing() { + initHdrModifier(null) + + assertThat(testInjector.registeredContentObserver).isNull() + } + + @Test + fun contentObserverNotRegisteredOnInit_allowedInLowPowerMode() { + initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = true)) + + assertThat(testInjector.registeredContentObserver).isNull() + } + + @Test + fun contentObserverRegisteredOnInit_notAllowedInLowPowerMode() { + initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = false)) + + assertThat(testInjector.registeredContentObserver).isNotNull() + } + + @Test + fun testNoHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( @@ -131,7 +151,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test NBM_HDR mode`() { + fun testNbmHdrMode() { initHdrModifier() // screen size = 10_000 val transitionPoint = 0.55f @@ -157,7 +177,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test HBM_HDR mode`() { + fun testHbmHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( @@ -182,7 +202,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test display change no HDR content`() { + fun testDisplayChange_noHdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) assertModifierState() @@ -195,7 +215,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test display change with HDR content`() { + fun testDisplayChange_hdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) setupHdrLayer(width = 100, height = 100, maxHdrRatio = 5f) @@ -218,7 +238,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test ambient lux decrease above maxBrightnessLimits no HDR`() { + fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( @@ -234,7 +254,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test ambient lux decrease above maxBrightnessLimits with HDR`() { + fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 200, height = 200, hdrBrightnessData = createHdrBrightnessData( @@ -260,7 +280,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test ambient lux decrease below maxBrightnessLimits no HDR`() { + fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( @@ -276,7 +296,7 @@ class HdrBrightnessModifierTest { } @Test - fun `test ambient lux decrease below maxBrightnessLimits with HDR`() { + fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) val maxBrightness = 0.6f @@ -322,6 +342,23 @@ class HdrBrightnessModifierTest { ) } + @Test + fun testLowPower_notAllowedInLowPower() { + initHdrModifier() + setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( + allowInLowPowerMode = false + )) + setupHdrLayer(width = 100, height = 100) + clearInvocations(mockChangeListener) + + testInjector.isLowPower = true + testInjector.registeredContentObserver!!.onChange(true) + + verify(mockChangeListener).onChanged() + assertModifierState() + } + + // Helper functions private fun setupHdrLayer(width: Int = 100, height: Int = 100, maxHdrRatio: Float = 0.8f) { testInjector.registeredHdrListener!!.onHdrInfoChanged( mockDisplayBinder, 1, width, height, 0, maxHdrRatio @@ -345,7 +382,6 @@ class HdrBrightnessModifierTest { width = width, height = height )) - testHandler.flush() } private fun initHdrModifier(hdrBrightnessData: HdrBrightnessData? = createHdrBrightnessData()) { @@ -384,9 +420,12 @@ class HdrBrightnessModifierTest { assertThat(stateBuilder.customAnimationRate).isEqualTo(animationRate) } - internal class TestInjector : Injector() { + internal class TestInjector(context: Context) : Injector(context) { var registeredHdrListener: SurfaceControlHdrLayerInfoListener? = null var registeredToken: IBinder? = null + var registeredContentObserver: ContentObserver? = null + + var isLowPower: Boolean = false override fun registerHdrListener( listener: SurfaceControlHdrLayerInfoListener, token: IBinder @@ -401,5 +440,17 @@ class HdrBrightnessModifierTest { registeredHdrListener = null registeredToken = null } + + override fun registerContentObserver(observer: ContentObserver, uri: Uri) { + registeredContentObserver = observer + } + + override fun unregisterContentObserver(observer: ContentObserver) { + registeredContentObserver = null + } + + override fun isLowPowerMode(): Boolean { + return isLowPower + } } }
\ No newline at end of file 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 2d4dbb77343e..78c9372599e1 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 @@ -479,6 +479,15 @@ public class FaceAuthenticationClientTest { eq(mContext.getOpPackageName()), anyInt(), anyInt(), any()); } + @Test + public void testCancelAuth_whenClientWaitingForCookie() throws RemoteException { + final FaceAuthenticationClient client = createClient(true); + client.waitForCookie(mCallback); + client.cancel(); + + verify(mCallback).onClientFinished(client, false); + } + private FaceAuthenticationClient createClient() throws RemoteException { return createClient(2 /* version */, mClientMonitorCallbackConverter, false /* allowBackgroundAuthentication */, true /* isBiometricPrompt */, 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 6ec888cd2e45..7e1d42117944 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 @@ -117,7 +117,6 @@ public class FingerprintAuthenticationClientTest { private static final int TOUCH_Y = 20; private static final float TOUCH_MAJOR = 4.4f; private static final float TOUCH_MINOR = 5.5f; - private static final int FINGER_UP = 111; @Rule public final TestableContext mContext = new TestableContext( @@ -383,6 +382,8 @@ public class FingerprintAuthenticationClientTest { @Test public void subscribeContextAndStartHal() throws RemoteException { + when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal); + final FingerprintAuthenticationClient client = createClient(); client.start(mCallback); @@ -691,6 +692,17 @@ public class FingerprintAuthenticationClientTest { verify(mLockoutTracker).addFailedAttemptForUser(USER_ID); } + @Test + public void testCancelAuth_whenClientWaitingForCookie() throws RemoteException { + final FingerprintAuthenticationClient client = createClientWithoutBackgroundAuth(); + client.waitForCookie(mCallback); + client.cancel(); + mLooper.moveTimeForward(10); + mLooper.dispatchAll(); + + verify(mCallback).onClientFinished(client, false); + } + private FingerprintAuthenticationClient createClient() throws RemoteException { return createClient(100 /* version */, true /* allowBackgroundAuthentication */, true /* isBiometricPrompt */, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0468f48379cb..e57a95e9161c 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -10038,6 +10038,19 @@ public class CarrierConfigManager { "carrier_supported_satellite_notification_hysteresis_sec_int"; /** + * An integer key holds the timeout duration in seconds used to determine whether to exit + * carrier-roaming NB-IOT satellite mode. + * + * The timer is started when the device screen is turned off during a satellite session. + * When the timer expires, the device exits Carrier Roaming NB IOT NTN. + * + * The default value is 30 seconds. + */ + @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) + public static final String KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT = + "satellite_screen_off_inactivity_timeout_duration_sec_int"; + + /** * Indicating whether DUN APN should be disabled when the device is roaming. In that case, * the default APN (i.e. internet) will be used for tethering. * @@ -11197,6 +11210,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false); sDefaults.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, 0); sDefaults.putInt(KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT, 180); + sDefaults.putInt(KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT, 30); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false); sDefaults.putBoolean(KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL, false); |