Merge "Fix a bug in ContrastColorUtil that was copying NoCopySpan." into main
diff --git a/core/api/current.txt b/core/api/current.txt
index c5a70df..3c5a31c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -43911,6 +43911,7 @@
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 c091062..109b0a8 100644
--- a/core/java/android/hardware/display/BrightnessInfo.java
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -60,7 +60,8 @@
@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 0000000..c154059
--- /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 49d9029..eea3de8 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 1eb2458..e6807ac 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 8669af3..0a8166f 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 2493e98..6d63971 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 @@
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 a6be640..4cd2fd0 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.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 @@
/**
* 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 @@
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 08de900..271c07d 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 @@
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.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 @@
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 @@
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 da1af0d..9cfbde4 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 @@
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 @@
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 7175ec4..2bb172f 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.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 @@
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 54f908b..da7e03f 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 @@
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 @@
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 b857556..c4af148 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 @@
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 @@
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 ecd5eda..633067d 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.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 @@
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 @@
Optional<DesktopTasksController> desktopTasksController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
InteractionJankMonitor interactionJankMonitor,
- AppToWebGenericLinksParser genericLinksParser
+ AppToWebGenericLinksParser genericLinksParser,
+ MultiInstanceHelper multiInstanceHelper
) {
this(
context,
@@ -223,6 +226,7 @@
transitions,
desktopTasksController,
genericLinksParser,
+ multiInstanceHelper,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
SurfaceControl.Transaction::new,
@@ -249,6 +253,7 @@
Transitions transitions,
Optional<DesktopTasksController> desktopTasksController,
AppToWebGenericLinksParser genericLinksParser,
+ MultiInstanceHelper multiInstanceHelper,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
Supplier<SurfaceControl.Transaction> transactionFactory,
@@ -268,6 +273,7 @@
mSyncQueue = syncQueue;
mTransitions = transitions;
mDesktopTasksController = desktopTasksController.get();
+ mMultiInstanceHelper = multiInstanceHelper;
mShellCommandHandler = shellCommandHandler;
mWindowManager = windowManager;
mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
@@ -536,6 +542,9 @@
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 @@
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 df41d31..b888344 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.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 @@
// 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 @@
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 @@
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 @@
mGenericLinksParser = genericLinksParser;
mMaximizeMenuFactory = maximizeMenuFactory;
mHandleMenuFactory = handleMenuFactory;
+ mMultiInstanceHelper = multiInstanceHelper;
}
/**
@@ -966,6 +972,9 @@
mDisplayController,
splitScreenController,
DesktopModeStatus.canEnterDesktopMode(mContext),
+ Flags.enableDesktopWindowingMultiInstanceFeatures()
+ && mMultiInstanceHelper
+ .supportsMultiInstanceSplit(mTaskInfo.baseActivity),
getBrowserLink(),
mResult.mCaptionWidth,
mResult.mCaptionHeight,
@@ -1274,7 +1283,8 @@
Choreographer choreographer,
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
- AppToWebGenericLinksParser genericLinksParser) {
+ AppToWebGenericLinksParser genericLinksParser,
+ MultiInstanceHelper multiInstanceHelper) {
return new DesktopModeWindowDecoration(
context,
userContext,
@@ -1288,7 +1298,8 @@
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 7a81d4c..74a6407 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 @@
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 @@
* 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 @@
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 @@
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 @@
displayController: DisplayController,
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
+ shouldShowNewWindowButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -536,6 +557,7 @@
displayController: DisplayController,
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
+ shouldShowNewWindowButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -551,6 +573,7 @@
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 e264160..c3a0bd9 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.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 @@
@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 @@
mockTransitions,
Optional.of(mockDesktopTasksController),
mockGenericLinksParser,
+ mockMultiInstanceHelper,
mockDesktopModeWindowDecorFactory,
mockInputMonitorFactory,
transactionFactory,
@@ -659,8 +662,9 @@
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 04b1eed..e60eb77 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.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 @@
private HandleMenu mMockHandleMenu;
@Mock
private HandleMenuFactory mMockHandleMenuFactory;
+ private MultiInstanceHelper mMockMultiInstanceHelper;
@Captor
private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener;
@Captor
@@ -218,7 +220,8 @@
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 @@
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 @@
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 ed43aa3..cca83dd 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 @@
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 6e53012..062e9b8 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 @@
* 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 bd1a442..e81d5d5 100644
--- a/packages/SystemUI/aconfig/biometrics_framework.aconfig
+++ b/packages/SystemUI/aconfig/biometrics_framework.aconfig
@@ -4,13 +4,6 @@
# 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 34fbcac..40fb769 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.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 @@
@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 @@
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 0352da3..9521be1 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 @@
});
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- setFocusableInTouchMode(true);
requestFocus();
}
@@ -464,7 +463,8 @@
}
}
- 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 b1cba2f..874ad9e 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.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 @@
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 6ed84e5..89fce4a 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 @@
if (shouldUseFloatBrightness()) {
mDozeService.setDozeScreenBrightnessFloat(
clampToDimBrightnessForScreenOffFloat(
- clampToUserSettingFloat(mDefaultDozeBrightnessFloat)));
+ clampToUserSettingOrAutoBrightnessFloat(mDefaultDozeBrightnessFloat)));
} else {
mDozeService.setDozeScreenBrightness(
clampToDimBrightnessForScreenOff(
- clampToUserSetting(mDefaultDozeBrightness)));
+ clampToUserSettingOrAutoBrightness(mDefaultDozeBrightness)));
}
mDozeHost.setAodDimmingScrim(0f);
}
@@ -310,10 +310,7 @@
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 @@
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 29450a2..3fe3162 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.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 @@
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 1e3ee28..dc69cda 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.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 @@
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 @@
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 e603db4..b8b93c9 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.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 @@
}
@Test
- @EnableFlags(FLAG_BP_TALKBACK)
fun hint_for_talkback_guidance() = runGenericTest {
val hint by collectLastValue(kosmos.promptViewModel.accessibilityHint)
@@ -1379,7 +1377,6 @@
}
@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 4818119..86da203 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 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 @@
@Mock
DozeParameters mDozeParameters;
@Mock
- DockManager mDockManager;
- @Mock
DevicePostureController mDevicePostureController;
@Mock
DozeLog mDozeLog;
@@ -114,8 +111,8 @@
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 @@
}
@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 @@
}
@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 ff65887..e3a38a8 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.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 @@
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 @@
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 191a048..a5fbfb5 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 @@
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.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.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 @@
@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 7f964d1..e5e04dc 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 @@
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 @@
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 8614fc9..e6bd24b 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.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 @@
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 03fbfd37..f936b81 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 @@
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 ef7abdd..6cce722 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 @@
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 d04afdb..dee4b4f 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 @@
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 12c3197..59fffe7 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 @@
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 ae1801c..4ab4336 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 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 @@
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 @@
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 @@
private final Runnable mDebouncer;
private IBinder mRegisteredDisplayToken;
+ private boolean mContentObserverRegistered = false;
private DisplayDeviceConfig mDisplayDeviceConfig;
@Nullable
@@ -73,6 +85,8 @@
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 @@
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 @@
mMaxBrightness = mPendingMaxBrightness;
mClamperChangeListener.onChanged();
};
+ mContentObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ onLowPowerModeChange();
+ }
+ };
mHandler.post(() -> onDisplayChanged(displayData));
}
@@ -135,12 +155,14 @@
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 @@
} 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 @@
}
// 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 @@
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 @@
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 @@
}
// 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 @@
// 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 @@
}
}
+ // 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 @@
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 730077c..61d8e0b 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 @@
case Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD: {
if (!mNewInputMethodSwitcherMenuEnabled) {
if (userId == mCurrentUserId) {
- mMenuController.updateKeyboardFromSettingsLocked();
+ mMenuController.updateKeyboardFromSettingsLocked(userId);
}
}
break;
@@ -693,7 +693,7 @@
senderUserId);
}
} else {
- mMenuController.hideInputMethodMenu();
+ mMenuController.hideInputMethodMenu(senderUserId);
}
} else {
Slog.w(TAG, "Unexpected intent " + intent);
@@ -1222,12 +1222,6 @@
}
}
- @GuardedBy("ImfLock.class")
- @UserIdInt
- int getCurrentImeUserIdLocked() {
- return mCurrentUserId;
- }
-
private final class InkWindowInitializer implements Runnable {
public void run() {
synchronized (ImfLock.class) {
@@ -1239,12 +1233,11 @@
}
}
- 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 @@
if (mNewInputMethodSwitcherMenuEnabled) {
mMenuControllerNew.hide(bindingController.getCurTokenDisplayId(), userId);
} else {
- mMenuController.hideInputMethodMenuLocked();
+ mMenuController.hideInputMethodMenuLocked(userId);
}
}
}
@@ -2860,7 +2853,7 @@
void updateFromSettingsLocked(boolean enabledMayChange, @UserIdInt int userId) {
updateInputMethodsFromSettingsLocked(enabledMayChange, userId);
if (!mNewInputMethodSwitcherMenuEnabled) {
- mMenuController.updateKeyboardFromSettingsLocked();
+ mMenuController.updateKeyboardFromSettingsLocked(userId);
}
}
@@ -3465,7 +3458,7 @@
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 @@
// other toolTypes are irrelevant and reported as unknown.
toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
}
- onUpdateEditorToolType(toolType);
+ onUpdateEditorToolTypeLocked(toolType);
}
@Override
@@ -5071,7 +5064,7 @@
mMenuControllerNew.show(menuItems, selectedIndex, displayId, userId);
} else {
mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId,
- lastInputMethodId, lastInputMethodSubtypeId, imList);
+ lastInputMethodId, lastInputMethodSubtypeId, imList, userId);
}
}
@@ -5948,7 +5941,7 @@
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 ba5c13e..f16a5a0 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 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 @@
@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 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 @@
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 @@
}
mService.setInputMethodLocked(im.getId(), subtypeId, userId);
}
- hideInputMethodMenuLocked();
+ hideInputMethodMenuLocked(userId);
}
};
mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
@@ -209,10 +209,10 @@
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 @@
/**
* 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 @@
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 0ed96ae..bb025cc 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 @@
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 @@
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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@Test
- fun `test NBM_HDR mode`() {
+ fun testNbmHdrMode() {
initHdrModifier()
// screen size = 10_000
val transitionPoint = 0.55f
@@ -157,7 +177,7 @@
}
@Test
- fun `test HBM_HDR mode`() {
+ fun testHbmHdrMode() {
initHdrModifier()
// screen size = 10_000
setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData(
@@ -182,7 +202,7 @@
}
@Test
- fun `test display change no HDR content`() {
+ fun testDisplayChange_noHdrContent() {
initHdrModifier()
setupDisplay(width = 100, height = 100)
assertModifierState()
@@ -195,7 +215,7 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
)
}
+ @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 @@
width = width,
height = height
))
- testHandler.flush()
}
private fun initHdrModifier(hdrBrightnessData: HdrBrightnessData? = createHdrBrightnessData()) {
@@ -384,9 +420,12 @@
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 @@
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 2d4dbb7..78c9372 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 @@
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 6ec888c..7e1d421 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 @@
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 @@
@Test
public void subscribeContextAndStartHal() throws RemoteException {
+ when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal);
+
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
@@ -691,6 +692,17 @@
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 0468f48..e57a95e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10038,6 +10038,19 @@
"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 @@
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);