Merge "Fix lastDispatchedState sources change" into main
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7926afe..f30a9f5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -6367,6 +6367,33 @@
Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
}
+ private static final String CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY =
+ PropertyInvalidatedCache.createPropertyName(
+ PropertyInvalidatedCache.MODULE_SYSTEM, "user_serial_number");
+
+ private final PropertyInvalidatedCache<Integer, Integer> mUserSerialNumberCache =
+ new PropertyInvalidatedCache<Integer, Integer>(
+ 32, CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY) {
+ @Override
+ public Integer recompute(Integer query) {
+ try {
+ return mService.getUserSerialNumber(query);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ @Override
+ public boolean bypass(Integer query) {
+ return query <= 0;
+ }
+ };
+
+
+ /** @hide */
+ public static final void invalidateUserSerialNumberCache() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY);
+ }
+
/**
* Returns a serial number on this device for a given userId. User handles can be recycled
* when deleting and creating users, but serial numbers are not reused until the device is wiped.
@@ -6376,6 +6403,14 @@
*/
@UnsupportedAppUsage
public int getUserSerialNumber(@UserIdInt int userId) {
+ if (android.multiuser.Flags.cacheUserSerialNumber()) {
+ // System user serial number is always 0, and it always exists.
+ // There is no need to call binder for that.
+ if (userId == UserHandle.USER_SYSTEM) {
+ return UserHandle.USER_SERIAL_SYSTEM;
+ }
+ return mUserSerialNumberCache.query(userId);
+ }
try {
return mService.getUserSerialNumber(userId);
} catch (RemoteException re) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 217b1d3..1bf1259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -19,6 +19,8 @@
package com.android.wm.shell.desktopmode
import android.app.ActivityManager.RunningTaskInfo
+import android.app.TaskInfo
+import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
import android.content.pm.ActivityInfo.isFixedOrientationLandscape
import android.content.pm.ActivityInfo.isFixedOrientationPortrait
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
@@ -105,7 +107,7 @@
* Calculates the largest size that can fit in a given area while maintaining a specific aspect
* ratio.
*/
-private fun maximumSizeMaintainingAspectRatio(
+fun maximumSizeMaintainingAspectRatio(
taskInfo: RunningTaskInfo,
targetArea: Size,
aspectRatio: Float
@@ -114,7 +116,8 @@
val targetWidth = targetArea.width
val finalHeight: Int
val finalWidth: Int
- if (isFixedOrientationPortrait(taskInfo.topActivityInfo!!.screenOrientation)) {
+ // Get orientation either through top activity or task's orientation
+ if (taskInfo.hasPortraitTopActivity()) {
val tempWidth = (targetHeight / aspectRatio).toInt()
if (tempWidth <= targetWidth) {
finalHeight = targetHeight
@@ -137,7 +140,7 @@
}
/** Calculates the aspect ratio of an activity from its fullscreen bounds. */
-private fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
+fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
if (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed) {
val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxWidth
val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxHeight
@@ -171,3 +174,41 @@
desiredSize.height + heightOffset
)
}
+
+/**
+ * Adjusts bounds to be positioned in the middle of the area provided, not necessarily the
+ * entire screen, as area can be offset by left and top start.
+ */
+fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart: Int): Rect {
+ val heightOffset = (areaBounds.height() - desiredSize.height) / 2
+ val widthOffset = (areaBounds.width() - desiredSize.width) / 2
+
+ val newLeft = leftStart + widthOffset
+ val newTop = topStart + heightOffset
+ val newRight = newLeft + desiredSize.width
+ val newBottom = newTop + desiredSize.height
+
+ return Rect(newLeft, newTop, newRight, newBottom)
+}
+
+fun TaskInfo.hasPortraitTopActivity(): Boolean {
+ val topActivityScreenOrientation =
+ topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED
+ val appBounds = configuration.windowConfiguration.appBounds
+
+ return when {
+ // First check if activity has portrait screen orientation
+ topActivityScreenOrientation != SCREEN_ORIENTATION_UNSPECIFIED -> {
+ isFixedOrientationPortrait(topActivityScreenOrientation)
+ }
+
+ // Then check if the activity is portrait when letterboxed
+ appCompatTaskInfo.topActivityBoundsLetterboxed -> appCompatTaskInfo.isTopActivityPillarboxed
+
+ // Then check if the activity is portrait
+ appBounds != null -> appBounds.height() > appBounds.width()
+
+ // Otherwise just take the orientation of the task
+ else -> isFixedOrientationPortrait(configuration.orientation)
+ }
+}
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 5813f85..d8e8c57 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
@@ -36,6 +36,7 @@
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
+import android.util.Size
import android.view.Display.DEFAULT_DISPLAY
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
@@ -649,13 +650,21 @@
fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) {
val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
- val stableBounds = Rect()
- displayLayout.getStableBounds(stableBounds)
+ val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
+ val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
val destinationBounds = Rect()
- if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
- // The desktop task is currently occupying the whole stable bounds. If the bounds
- // before the task was toggled to stable bounds were saved, toggle the task to those
- // bounds. Otherwise, toggle to the default bounds.
+
+ val isMaximized = if (taskInfo.isResizeable) {
+ currentTaskBounds == stableBounds
+ } else {
+ currentTaskBounds.width() == stableBounds.width()
+ || currentTaskBounds.height() == stableBounds.height()
+ }
+
+ if (isMaximized) {
+ // The desktop task is at the maximized width and/or height of the stable bounds.
+ // If the task's pre-maximize stable bounds were saved, toggle the task to those bounds.
+ // Otherwise, toggle to the default bounds.
val taskBoundsBeforeMaximize =
desktopModeTaskRepository.removeBoundsBeforeMaximize(taskInfo.taskId)
if (taskBoundsBeforeMaximize != null) {
@@ -670,9 +679,20 @@
} else {
// Save current bounds so that task can be restored back to original bounds if necessary
// and toggle to the stable bounds.
- val taskBounds = taskInfo.configuration.windowConfiguration.bounds
- desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, taskBounds)
- destinationBounds.set(stableBounds)
+ desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)
+
+ if (taskInfo.isResizeable) {
+ // if resizable then expand to entire stable bounds (full display minus insets)
+ destinationBounds.set(stableBounds)
+ } else {
+ // if non-resizable then calculate max bounds according to aspect ratio
+ val activityAspectRatio = calculateAspectRatio(taskInfo)
+ val newSize = maximumSizeMaintainingAspectRatio(taskInfo,
+ Size(stableBounds.width(), stableBounds.height()), activityAspectRatio)
+ val newBounds = centerInArea(
+ newSize, stableBounds, stableBounds.left, stableBounds.top)
+ destinationBounds.set(newBounds)
+ }
}
val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index c671fbe..b5a6d83 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -48,6 +48,8 @@
fun setup() {
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+ // TODO: b/349075982 - Remove once launcher rotation and checks are stable.
+ tapl.setExpectedRotationCheckEnabled(false)
SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, rotation)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 5f36e9a..0bcbe13 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -1916,6 +1916,26 @@
}
@Test
+ fun toggleBounds_togglesToCalculatedBoundsForNonResizable() {
+ val bounds = Rect(0, 0, 200, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply {
+ topActivityInfo = ActivityInfo().apply {
+ screenOrientation = SCREEN_ORIENTATION_LANDSCAPE
+ configuration.windowConfiguration.appBounds = bounds
+ }
+ isResizeable = false
+ }
+
+ // Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds
+ val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750)
+
+ controller.toggleDesktopTaskSize(task)
+ // Assert bounds set to stable bounds
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
+ }
+
+ @Test
fun toggleBounds_lastBoundsBeforeMaximizeSaved() {
val bounds = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
@@ -1942,6 +1962,46 @@
}
@Test
+ fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualWidth() {
+ val boundsBeforeMaximize = Rect(0, 0, 100, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply {
+ isResizeable = false
+ }
+
+ // Maximize
+ controller.toggleDesktopTaskSize(task)
+ task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left,
+ boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom)
+
+ // Restore
+ controller.toggleDesktopTaskSize(task)
+
+ // Assert bounds set to last bounds before maximize
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
+ }
+
+ @Test
+ fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualHeight() {
+ val boundsBeforeMaximize = Rect(0, 0, 100, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply {
+ isResizeable = false
+ }
+
+ // Maximize
+ controller.toggleDesktopTaskSize(task)
+ task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left,
+ STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom)
+
+ // Restore
+ controller.toggleDesktopTaskSize(task)
+
+ // Assert bounds set to last bounds before maximize
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
+ }
+
+ @Test
fun toggleBounds_removesLastBoundsBeforeMaximizeAfterRestoringBounds() {
val boundsBeforeMaximize = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 275c930..0f9c344 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -67,7 +67,7 @@
/**
* Represent a logical device of type TV residing in Android system.
*/
-public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDeviceTv";
// Whether ARC is available or not. "true" means that ARC is established between TV and
@@ -113,6 +113,18 @@
// handle.
private final DelayedMessageBuffer mDelayedMessageBuffer = new DelayedMessageBuffer(this);
+ private boolean mWasActiveSourceSetToConnectedDevice = false;
+
+ @VisibleForTesting
+ protected boolean getWasActiveSourceSetToConnectedDevice() {
+ return mWasActiveSourceSetToConnectedDevice;
+ }
+
+ protected void setWasActiveSourceSetToConnectedDevice(
+ boolean wasActiveSourceSetToConnectedDevice) {
+ mWasActiveSourceSetToConnectedDevice = wasActiveSourceSetToConnectedDevice;
+ }
+
// Defines the callback invoked when TV input framework is updated with input status.
// We are interested in the notification for HDMI input addition event, in order to
// process any CEC commands that arrived before the input is added.
@@ -474,6 +486,7 @@
|| info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
mService.getHdmiCecNetwork().updateDevicePowerStatus(logicalAddress,
HdmiControlManager.POWER_STATUS_ON);
+ setWasActiveSourceSetToConnectedDevice(true);
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
} else {
@@ -489,13 +502,16 @@
protected int handleStandby(HdmiCecMessage message) {
assertRunOnServiceThread();
- // Ignore <Standby> from non-active source device.
- if (getActiveSource().logicalAddress != message.getSource()) {
+ // If a device has previously asserted the active source status, ignore <Standby> from
+ // non-active source.
+ if (getWasActiveSourceSetToConnectedDevice()
+ && getActiveSource().logicalAddress != message.getSource()) {
Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
+ " Current active source has logical address "
+ getActiveSource().logicalAddress);
return Constants.HANDLED;
}
+ setWasActiveSourceSetToConnectedDevice(false);
return super.handleStandby(message);
}
@@ -1457,6 +1473,7 @@
invokeStandbyCompletedCallback(callback);
return;
}
+ setWasActiveSourceSetToConnectedDevice(false);
boolean sendStandbyOnSleep =
mService.getHdmiCecConfig().getIntValue(
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e0e8a03..e215ca3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5975,6 +5975,7 @@
@VisibleForTesting
void removeUserInfo(@UserIdInt int userId) {
synchronized (mUsersLock) {
+ UserManager.invalidateUserSerialNumberCache();
mUsers.remove(userId);
}
}
@@ -6400,6 +6401,7 @@
// Remove this user from the list
synchronized (mUsersLock) {
+ UserManager.invalidateUserSerialNumberCache();
mUsers.remove(userId);
mIsUserManaged.delete(userId);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7d7592f..5f19924 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8179,8 +8179,7 @@
}
void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
- if (mAppCompatController.getAppCompatOverrides()
- .getAppCompatOrientationOverrides()
+ if (mAppCompatController.getAppCompatOrientationOverrides()
.shouldIgnoreRequestedOrientation(requestedOrientation)) {
return;
}
@@ -8559,7 +8558,7 @@
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
final boolean isInCameraCompatFreeform = parentWindowingMode == WINDOWING_MODE_FREEFORM
- && mLetterboxUiController.getFreeformCameraCompatMode()
+ && mAppCompatController.getAppCompatCameraOverrides().getFreeformCameraCompatMode()
!= CAMERA_COMPAT_FREEFORM_NONE;
// Bubble activities should always fill their parent and should not be letterboxed.
@@ -9887,7 +9886,8 @@
return mLetterboxUiController.getUserMinAspectRatio();
}
if (!mLetterboxUiController.shouldOverrideMinAspectRatio()
- && !mLetterboxUiController.shouldOverrideMinAspectRatioForCamera()) {
+ && !mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera()) {
return info.getMinAspectRatio();
}
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
@@ -10814,15 +10814,18 @@
proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation());
proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus());
proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldForceRotateForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldRefreshActivityForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat());
proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
mLetterboxUiController.shouldOverrideMinAspectRatio());
proto.write(SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP,
- mAppCompatController.getAppCompatOverrides().getAppCompatOrientationOverrides()
+ mAppCompatController.getAppCompatOrientationOverrides()
.shouldIgnoreOrientationRequestLoop());
proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP,
mLetterboxUiController.shouldOverrideForceResizeApp());
diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java
index 056c09e..0c32dfc 100644
--- a/services/core/java/com/android/server/wm/ActivityRefresher.java
+++ b/services/core/java/com/android/server/wm/ActivityRefresher.java
@@ -77,10 +77,10 @@
final boolean cycleThroughStop =
mWmService.mLetterboxConfiguration
.isCameraCompatRefreshCycleThroughStopEnabled()
- && !activity.mLetterboxUiController
- .shouldRefreshActivityViaPauseForCameraCompat();
+ && !activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat();
- activity.mLetterboxUiController.setIsRefreshRequested(true);
+ activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(true);
ProtoLog.v(WM_DEBUG_STATES,
"Refreshing activity for freeform camera compatibility treatment, "
+ "activityRecord=%s", activity);
@@ -97,24 +97,26 @@
}
}, REFRESH_CALLBACK_TIMEOUT_MS);
} catch (RemoteException e) {
- activity.mLetterboxUiController.setIsRefreshRequested(false);
+ activity.mAppCompatController.getAppCompatCameraOverrides()
+ .setIsRefreshRequested(false);
}
}
boolean isActivityRefreshing(@NonNull ActivityRecord activity) {
- return activity.mLetterboxUiController.isRefreshRequested();
+ return activity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested();
}
void onActivityRefreshed(@NonNull ActivityRecord activity) {
// TODO(b/333060789): can we tell that refresh did not happen by observing the activity
// state?
- activity.mLetterboxUiController.setIsRefreshRequested(false);
+ activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(false);
}
private boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
@NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
return mWmService.mLetterboxConfiguration.isCameraCompatRefreshEnabled()
- && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && activity.mAppCompatController.getAppCompatOverrides()
+ .getAppCompatCameraOverrides().shouldRefreshActivityForCameraCompat()
&& ArrayUtils.find(mEvaluators.toArray(), evaluator ->
((Evaluator) evaluator)
.shouldRefreshActivity(activity, newConfig, lastReportedConfig)) != null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index dded1ca..ded205e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6192,11 +6192,14 @@
synchronized (mGlobalLockWithoutBoost) {
final WindowProcessController proc = mProcessNames.remove(name, uid);
if (proc != null && !mStartingProcessActivities.isEmpty()) {
- for (int i = mStartingProcessActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = mStartingProcessActivities.get(i);
+ // Use a copy in case finishIfPossible changes the list indirectly.
+ final ArrayList<ActivityRecord> activities =
+ new ArrayList<>(mStartingProcessActivities);
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = activities.get(i);
if (uid == r.info.applicationInfo.uid && name.equals(r.processName)) {
Slog.w(TAG, proc + " is removed with pending start " + r);
- mStartingProcessActivities.remove(i);
+ mStartingProcessActivities.remove(r);
// If visible, finish it to avoid getting stuck on screen.
if (r.isVisibleRequested()) {
r.finishIfPossible("starting-proc-removed", false /* oomAdj */);
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
new file mode 100644
index 0000000..c0e5005
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm;
+
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
+
+import com.android.server.wm.utils.OptPropFactory;
+import com.android.window.flags.Flags;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Encapsulates app compat configurations and overrides related to camera.
+ */
+class AppCompatCameraOverrides {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "AppCompatCameraOverrides" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+ @NonNull
+ private final AppCompatCameraOverridesState mAppCompatCameraOverridesState;
+ @NonNull
+ private final LetterboxConfiguration mLetterboxConfiguration;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowMinAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowRefreshOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp;
+
+ AppCompatCameraOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
+ mActivityRecord = activityRecord;
+ mLetterboxConfiguration = letterboxConfiguration;
+ mAppCompatCameraOverridesState = new AppCompatCameraOverridesState();
+ mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ final BooleanSupplier isCameraCompatTreatmentEnabled = AppCompatUtils.asLazy(
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
+ isCameraCompatTreatmentEnabled);
+ }
+
+ /**
+ * Whether we should apply the min aspect ratio per-app override only when an app is connected
+ * to the camera.
+ * When this override is applied the min aspect ratio given in the app's manifest will be
+ * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
+ * is higher. The treatment will also apply if no value is provided in the manifest.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideMinAspectRatioForCamera() {
+ return mActivityRecord.isCameraActive()
+ && mAllowMinAspectRatioOverrideOptProp
+ .shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
+ }
+
+ /**
+ * Whether activity is eligible for activity "refresh" after camera compat force rotation
+ * treatment. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityForCameraCompat() {
+ return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
+ }
+
+ /**
+ * Whether activity should be "refreshed" after the camera compat force rotation treatment
+ * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
+ * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
+ * component property by the app developers.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
+ * manufacturer with override / by the app developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityViaPauseForCameraCompat() {
+ return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
+ }
+
+ /**
+ * Whether activity is eligible for camera compat force rotation treatment. See {@link
+ * DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldForceRotateForCameraCompat() {
+ return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
+ }
+
+ /**
+ * Whether activity is eligible for camera compatibility free-form treatment.
+ *
+ * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
+ * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
+ * provides changes to the camera and display orientation signals to match those expected on a
+ * portrait device in that orientation (for example, on a standard phone).
+ *
+ * <p>The treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Property gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override.
+ * </ul>
+ */
+ boolean shouldApplyFreeformTreatmentForCameraCompat() {
+ return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
+ OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+ }
+
+ /**
+ * @return {@code true} if the configuration needs to be recomputed after a camera state update.
+ */
+ boolean shouldRecomputeConfigurationForCameraCompat() {
+ return isOverrideOrientationOnlyForCameraEnabled()
+ || isCameraCompatSplitScreenAspectRatioAllowed()
+ || shouldOverrideMinAspectRatioForCamera();
+ }
+
+ boolean isOverrideOrientationOnlyForCameraEnabled() {
+ return isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
+ }
+
+ /**
+ * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}.
+ */
+ boolean isRefreshRequested() {
+ return mAppCompatCameraOverridesState.mIsRefreshRequested;
+ }
+
+ /**
+ * @param isRequested Whether activity "refresh" was requested but not finished
+ * in {@link #activityResumedLocked}.
+ */
+ void setIsRefreshRequested(boolean isRequested) {
+ mAppCompatCameraOverridesState.mIsRefreshRequested = isRequested;
+ }
+
+ /**
+ * Whether we use split screen aspect ratio for the activity when camera compat treatment
+ * is active because the corresponding config is enabled and activity supports resizing.
+ */
+ boolean isCameraCompatSplitScreenAspectRatioAllowed() {
+ return mLetterboxConfiguration.isCameraCompatSplitScreenAspectRatioEnabled()
+ && !mActivityRecord.shouldCreateCompatDisplayInsets();
+ }
+
+ @FreeformCameraCompatMode
+ int getFreeformCameraCompatMode() {
+ return mAppCompatCameraOverridesState.mFreeformCameraCompatMode;
+ }
+
+ void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
+ mAppCompatCameraOverridesState.mFreeformCameraCompatMode = freeformCameraCompatMode;
+ }
+
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ static class AppCompatCameraOverridesState {
+ // Whether activity "refresh" was requested but not finished in
+ // ActivityRecord#activityResumedLocked following the camera compat force rotation in
+ // DisplayRotationCompatPolicy.
+ private boolean mIsRefreshRequested;
+
+ @FreeformCameraCompatMode
+ private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
new file mode 100644
index 0000000..ee523a2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+
+/**
+ * Encapsulate the app compat logic related to camera.
+ */
+class AppCompatCameraPolicy {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "AppCompatCameraPolicy" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ @NonNull
+ private final AppCompatCameraOverrides mAppCompatCameraOverrides;
+
+ AppCompatCameraPolicy(@NonNull ActivityRecord activityRecord,
+ @NonNull AppCompatCameraOverrides appCompatCameraOverrides) {
+ mActivityRecord = activityRecord;
+ mAppCompatCameraOverrides = appCompatCameraOverrides;
+ }
+
+ void recomputeConfigurationForCameraCompatIfNeeded() {
+ if (mAppCompatCameraOverrides.shouldRecomputeConfigurationForCameraCompat()) {
+ mActivityRecord.recomputeConfiguration();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 4b0d739..d8c0c17 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+
+import com.android.server.wm.utils.OptPropFactory;
/**
* Allows the interaction with all the app compat policies and configurations
@@ -28,19 +31,26 @@
private final AppCompatOrientationPolicy mOrientationPolicy;
@NonNull
private final AppCompatOverrides mAppCompatOverrides;
+ @NonNull
+ private final AppCompatCameraPolicy mAppCompatCameraPolicy;
AppCompatController(@NonNull WindowManagerService wmService,
@NonNull ActivityRecord activityRecord) {
+ final PackageManager packageManager = wmService.mContext.getPackageManager();
+ final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
+ activityRecord.packageName);
mTransparentPolicy = new TransparentPolicy(activityRecord,
wmService.mLetterboxConfiguration);
- mAppCompatOverrides = new AppCompatOverrides(wmService, activityRecord,
- wmService.mLetterboxConfiguration);
+ mAppCompatOverrides = new AppCompatOverrides(activityRecord,
+ wmService.mLetterboxConfiguration, optPropBuilder);
// TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with aspectRatio.
final LetterboxUiController tmpController = activityRecord.mLetterboxUiController;
mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord,
mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride,
tmpController::shouldApplyUserMinAspectRatioOverride,
tmpController::isSystemOverrideToFullscreenEnabled);
+ mAppCompatCameraPolicy = new AppCompatCameraPolicy(activityRecord,
+ mAppCompatOverrides.getAppCompatCameraOverrides());
}
@NonNull
@@ -54,7 +64,22 @@
}
@NonNull
+ AppCompatCameraPolicy getAppCompatCameraPolicy() {
+ return mAppCompatCameraPolicy;
+ }
+
+ @NonNull
AppCompatOverrides getAppCompatOverrides() {
return mAppCompatOverrides;
}
+
+ @NonNull
+ AppCompatOrientationOverrides getAppCompatOrientationOverrides() {
+ return mAppCompatOverrides.getAppCompatOrientationOverrides();
+ }
+
+ @NonNull
+ AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return mAppCompatOverrides.getAppCompatCameraOverrides();
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index 446a75c..b0fdbb5 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -28,7 +28,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.AppCompatOverrides.asLazy;
+import static com.android.server.wm.AppCompatUtils.asLazy;
import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
@@ -60,9 +60,9 @@
@NonNull
final OrientationOverridesState mOrientationOverridesState;
- AppCompatOrientationOverrides(@NonNull OptPropFactory optPropBuilder,
- @NonNull LetterboxConfiguration letterboxConfiguration,
- @NonNull ActivityRecord activityRecord) {
+ AppCompatOrientationOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
mActivityRecord = activityRecord;
mOrientationOverridesState = new OrientationOverridesState(mActivityRecord,
System::currentTimeMillis);
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
index 8e9a9e9..960ef5a 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -103,11 +103,11 @@
return candidate;
}
- if (displayContent != null && mAppCompatOverrides
+ if (displayContent != null && mAppCompatOverrides.getAppCompatCameraOverrides()
.isOverrideOrientationOnlyForCameraEnabled()
- && (displayContent.mDisplayRotationCompatPolicy == null
- || !displayContent.mDisplayRotationCompatPolicy
- .isActivityEligibleForOrientationOverride(mActivityRecord))) {
+ && (displayContent.mDisplayRotationCompatPolicy == null
+ || !displayContent.mDisplayRotationCompatPolicy
+ .isActivityEligibleForOrientationOverride(mActivityRecord))) {
return candidate;
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java
index 794008a..c20da7c 100644
--- a/services/core/java/com/android/server/wm/AppCompatOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java
@@ -19,22 +19,13 @@
import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
-import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
@@ -47,12 +38,8 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
-import android.content.pm.PackageManager;
import com.android.server.wm.utils.OptPropFactory;
-import com.android.window.flags.Flags;
-
-import java.util.function.BooleanSupplier;
/**
* Encapsulate logic related to operations guarded by an app override.
@@ -70,12 +57,6 @@
@NonNull
private final OptPropFactory.OptProp mFakeFocusOptProp;
@NonNull
- private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp;
- @NonNull
- private final OptPropFactory.OptProp mCameraCompatAllowRefreshOptProp;
- @NonNull
- private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp;
- @NonNull
private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp;
@NonNull
private final OptPropFactory.OptProp mAllowDisplayOrientationOverrideOptProp;
@@ -87,37 +68,25 @@
private final OptPropFactory.OptProp mAllowUserAspectRatioOverrideOptProp;
@NonNull
private final OptPropFactory.OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
-
+ @NonNull
private final AppCompatOrientationOverrides mAppCompatOrientationOverrides;
+ @NonNull
+ private final AppCompatCameraOverrides mAppCompatCameraOverrides;
- AppCompatOverrides(@NonNull WindowManagerService wmService,
- @NonNull ActivityRecord activityRecord,
- @NonNull LetterboxConfiguration letterboxConfiguration) {
+ AppCompatOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
mLetterboxConfiguration = letterboxConfiguration;
mActivityRecord = activityRecord;
- final PackageManager packageManager = wmService.mContext.getPackageManager();
- final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
- activityRecord.packageName);
-
- mAppCompatOrientationOverrides =
- new AppCompatOrientationOverrides(optPropBuilder, mLetterboxConfiguration,
- mActivityRecord);
+ mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord,
+ mLetterboxConfiguration, optPropBuilder);
+ mAppCompatCameraOverrides = new AppCompatCameraOverrides(mActivityRecord,
+ mLetterboxConfiguration, optPropBuilder);
mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
mLetterboxConfiguration::isCompatFakeFocusEnabled);
- final BooleanSupplier isCameraCompatTreatmentEnabled = asLazy(
- mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
- mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
- isCameraCompatTreatmentEnabled);
- mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
- isCameraCompatTreatmentEnabled);
- mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
- isCameraCompatTreatmentEnabled);
mAllowOrientationOverrideOptProp = optPropBuilder.create(
PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
@@ -162,6 +131,11 @@
return mAppCompatOrientationOverrides;
}
+ @NonNull
+ AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return mAppCompatCameraOverrides;
+ }
+
/**
* Whether sending compat fake focus for split screen resumed activities is enabled. Needed
* because some game engines wait to get focus before drawing the content of the app which isn't
@@ -179,57 +153,6 @@
isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS));
}
- /**
- * Whether activity is eligible for camera compat force rotation treatment. See {@link
- * DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldForceRotateForCameraCompat() {
- return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
- }
-
- /**
- * Whether activity is eligible for activity "refresh" after camera compat force rotation
- * treatment. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityForCameraCompat() {
- return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
- }
-
- /**
- * Whether activity should be "refreshed" after the camera compat force rotation treatment
- * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
- * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
- * component property by the app developers.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
- * manufacturer with override / by the app developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityViaPauseForCameraCompat() {
- return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
- }
-
boolean isSystemOverrideToFullscreenEnabled(int userAspectRatio) {
return isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER)
&& !mAllowOrientationOverrideOptProp.isFalse()
@@ -262,50 +185,6 @@
return isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
}
- boolean isOverrideOrientationOnlyForCameraEnabled() {
- return isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
- }
-
- /**
- * Whether activity is eligible for camera compatibility free-form treatment.
- *
- * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
- * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
- * provides changes to the camera and display orientation signals to match those expected on a
- * portrait device in that orientation (for example, on a standard phone).
- *
- * <p>The treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
- * </ul>
- */
- boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
- OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
- }
-
-
- /**
- * Whether we should apply the min aspect ratio per-app override only when an app is connected
- * to the camera.
- * When this override is applied the min aspect ratio given in the app's manifest will be
- * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
- * is higher. The treatment will also apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatioForCamera() {
- return mActivityRecord.isCameraActive()
- && mAllowMinAspectRatioOverrideOptProp
- .shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
- }
-
/**
* Whether should fix display orientation to landscape natural orientation when a task is
* fullscreen and the display is ignoring orientation requests.
@@ -382,21 +261,4 @@
private boolean isCompatChangeEnabled(long overrideChangeId) {
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
}
-
- @NonNull
- static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
- return new BooleanSupplier() {
- private boolean mRead;
- private boolean mValue;
-
- @Override
- public boolean getAsBoolean() {
- if (!mRead) {
- mRead = true;
- mValue = supplier.getAsBoolean();
- }
- return mValue;
- }
- };
- }
}
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
new file mode 100644
index 0000000..be51dd3b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Utilities for App Compat policies and overrides.
+ */
+class AppCompatUtils {
+
+ /**
+ * Lazy version of a {@link BooleanSupplier} which access an existing BooleanSupplier and
+ * caches the value.
+ *
+ * @param supplier The BooleanSupplier to decorate.
+ * @return A lazy implementation of a BooleanSupplier
+ */
+ @NonNull
+ static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
+ return new BooleanSupplier() {
+ private boolean mRead;
+ private boolean mValue;
+
+ @Override
+ public boolean getAsBoolean() {
+ if (!mRead) {
+ mRead = true;
+ mValue = supplier.getAsBoolean();
+ }
+ return mValue;
+ }
+ };
+ }
+}
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 9204017..68a4172 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -110,12 +110,14 @@
if (!isTreatmentEnabledForActivity(cameraActivity)) {
return false;
}
- final int existingCameraCompatMode =
- cameraActivity.mLetterboxUiController.getFreeformCameraCompatMode();
+ final int existingCameraCompatMode = cameraActivity.mAppCompatController
+ .getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode();
final int newCameraCompatMode = getCameraCompatMode(cameraActivity);
if (newCameraCompatMode != existingCameraCompatMode) {
mIsCameraCompatTreatmentPending = true;
- cameraActivity.mLetterboxUiController.setFreeformCameraCompatMode(newCameraCompatMode);
+ cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .setFreeformCameraCompatMode(newCameraCompatMode);
forceUpdateActivityAndTask(cameraActivity);
return true;
} else {
@@ -134,8 +136,8 @@
mDisplayContent.mDisplayId, cameraId);
return false;
}
- cameraActivity.mLetterboxUiController.setFreeformCameraCompatMode(
- CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE);
+ cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE);
forceUpdateActivityAndTask(cameraActivity);
mIsCameraCompatTreatmentPending = false;
return true;
@@ -191,6 +193,6 @@
|| mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
return false;
}
- return topActivity.mLetterboxUiController.isRefreshRequested();
+ return topActivity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index beb3767..3d71e95 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -228,9 +228,11 @@
!= lastReportedConfig.windowConfiguration.getDisplayRotation());
return isTreatmentEnabledForDisplay()
&& isTreatmentEnabledForActivity(activity)
- && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat()
&& (displayRotationChanged
- || activity.mLetterboxUiController.isCameraCompatSplitScreenAspectRatioAllowed());
+ || activity.mAppCompatController.getAppCompatCameraOverrides()
+ .isCameraCompatSplitScreenAspectRatioAllowed());
}
/**
@@ -254,7 +256,8 @@
boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
return isTreatmentEnabledForDisplay()
&& isCameraActive(activity, /* mustBeFullscreen */ true)
- && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat();
}
/**
@@ -286,7 +289,8 @@
// handle dynamic changes so we shouldn't force rotate them.
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
- && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat();
}
@Override
@@ -295,7 +299,8 @@
// Checking whether an activity in fullscreen rather than the task as this camera
// compat treatment doesn't cover activity embedding.
if (cameraActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- cameraActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
+ cameraActivity.mAppCompatController
+ .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
return true;
}
@@ -362,7 +367,8 @@
|| topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return true;
}
- topActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
+ topActivity.mAppCompatController
+ .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
return true;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index f70d2a5..872b4e1 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
@@ -657,7 +656,6 @@
final boolean lastKeyguardGoingAway = mKeyguardGoingAway;
final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity;
- final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
mRequestDismissKeyguard = false;
mOccluded = false;
@@ -666,7 +664,6 @@
mDismissingKeyguardActivity = null;
mTopTurnScreenOnActivity = null;
- boolean occludedByActivity = false;
final Task task = getRootTaskForControllingOccluding(display);
final ActivityRecord top = task != null ? task.getTopNonFinishingActivity() : null;
if (top != null) {
@@ -712,7 +709,7 @@
if (mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity)) {
+ && (mRequestDismissKeyguard || mOccluded)) {
controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 85eeab1..e924fb6 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
@@ -65,7 +64,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
-import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -113,18 +111,10 @@
@Nullable
private Letterbox mLetterbox;
- // Whether activity "refresh" was requested but not finished in
- // ActivityRecord#activityResumedLocked following the camera compat force rotation in
- // DisplayRotationCompatPolicy.
- private boolean mIsRefreshRequested;
-
private boolean mLastShouldShowLetterboxUi;
private boolean mDoubleTapEvent;
- @FreeformCameraCompatMode
- private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
-
LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) {
mLetterboxConfiguration = wmService.mLetterboxConfiguration;
// Given activityRecord may not be fully constructed since LetterboxUiController
@@ -147,13 +137,6 @@
}
}
-
- @VisibleForTesting
- int getSetOrientationRequestCounter() {
- return getAppCompatOverrides().getAppCompatOrientationOverrides()
- .getSetOrientationRequestCounter();
- }
-
/**
* Whether sending compat fake focus for split screen resumed activities is enabled. Needed
* because some game engines wait to get focus before drawing the content of the app which isn't
@@ -187,23 +170,6 @@
}
/**
- * Whether we should apply the min aspect ratio per-app override only when an app is connected
- * to the camera.
- * When this override is applied the min aspect ratio given in the app's manifest will be
- * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
- * is higher. The treatment will also apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatioForCamera() {
- return getAppCompatOverrides().shouldOverrideMinAspectRatioForCamera();
- }
-
- /**
* Whether we should apply the force resize per-app override. When this override is applied it
* forces the packages it is applied to to be resizable. It won't change whether the app can be
* put into multi-windowing mode, but allow the app to resize without going into size-compat
@@ -242,16 +208,6 @@
.setRelaunchingAfterRequestedOrientationChanged(isRelaunching);
}
- /**
- * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}.
- */
- boolean isRefreshRequested() {
- return mIsRefreshRequested;
- }
-
- void setIsRefreshRequested(boolean isRequested) {
- mIsRefreshRequested = isRequested;
- }
boolean isOverrideRespectRequestedOrientationEnabled() {
return getAppCompatOverrides().isOverrideRespectRequestedOrientationEnabled();
@@ -274,85 +230,6 @@
return getAppCompatOverrides().shouldUseDisplayLandscapeNaturalOrientation();
}
- boolean isOverrideOrientationOnlyForCameraEnabled() {
- return getAppCompatOverrides().isOverrideOrientationOnlyForCameraEnabled();
- }
-
- /**
- * Whether activity is eligible for activity "refresh" after camera compat force rotation
- * treatment. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityForCameraCompat() {
- return getAppCompatOverrides().shouldRefreshActivityForCameraCompat();
- }
-
- /**
- * Whether activity should be "refreshed" after the camera compat force rotation treatment
- * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
- * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
- * component property by the app developers.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
- * manufacturer with override / by the app developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityViaPauseForCameraCompat() {
- return getAppCompatOverrides().shouldRefreshActivityViaPauseForCameraCompat();
- }
-
- /**
- * Whether activity is eligible for camera compat force rotation treatment. See {@link
- * DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldForceRotateForCameraCompat() {
- return getAppCompatOverrides().shouldForceRotateForCameraCompat();
- }
-
- /**
- * Whether activity is eligible for camera compatibility free-form treatment.
- *
- * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
- * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
- * provides changes to the camera and display orientation signals to match those expected on a
- * portrait device in that orientation (for example, on a standard phone).
- *
- * <p>The treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
- * </ul>
- */
- boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return getAppCompatOverrides().shouldApplyFreeformTreatmentForCameraCompat();
- }
-
- @FreeformCameraCompatMode
- int getFreeformCameraCompatMode() {
- return mFreeformCameraCompatMode;
- }
-
- void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
- mFreeformCameraCompatMode = freeformCameraCompatMode;
- }
-
private boolean isCompatChangeEnabled(long overrideChangeId) {
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
}
@@ -574,27 +451,10 @@
: getDefaultMinAspectRatio();
}
- void recomputeConfigurationForCameraCompatIfNeeded() {
- if (isOverrideOrientationOnlyForCameraEnabled()
- || isCameraCompatSplitScreenAspectRatioAllowed()
- || shouldOverrideMinAspectRatioForCamera()) {
- mActivityRecord.recomputeConfiguration();
- }
- }
-
boolean isLetterboxEducationEnabled() {
return mLetterboxConfiguration.getIsEducationEnabled();
}
- /**
- * Whether we use split screen aspect ratio for the activity when camera compat treatment
- * is active because the corresponding config is enabled and activity supports resizing.
- */
- boolean isCameraCompatSplitScreenAspectRatioAllowed() {
- return mLetterboxConfiguration.isCameraCompatSplitScreenAspectRatioEnabled()
- && !mActivityRecord.shouldCreateCompatDisplayInsets();
- }
-
private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) {
final boolean isBookMode = isDisplayFullScreenAndInPosture(/* isTabletop */ false);
final boolean isNotCenteredHorizontally = getHorizontalPositionMultiplier(
@@ -605,8 +465,9 @@
// Don't resize to split screen size when in book mode if letterbox position is centered
return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
- || isCameraCompatSplitScreenAspectRatioAllowed()
- && getAppCompatOverrides().isCameraCompatTreatmentActive();
+ || mActivityRecord.mAppCompatController.getAppCompatCameraOverrides()
+ .isCameraCompatSplitScreenAspectRatioAllowed()
+ && getAppCompatOverrides().isCameraCompatTreatmentActive();
}
private float getDefaultMinAspectRatioForUnresizableApps() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 52a1ed9..f0b0e91 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3522,7 +3522,8 @@
appCompatTaskInfo.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top == null
? CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE
- : top.mLetterboxUiController.getFreeformCameraCompatMode();
+ : top.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 2a4b797..21364b8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -2012,38 +2012,94 @@
}
@Test
- public void handleStandby_fromActiveSource_standby() {
- mPowerManager.setInteractive(true);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ public void handleStandby_fromActiveSource_previousActiveSourceSet_standby() {
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ HdmiCecMessage activeSourceFromPlayback =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x1000);
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ mPowerManager.setInteractive(true);
+ mTestLooper.dispatchAll();
+
+ mHdmiCecLocalDeviceTv.dispatchMessage(activeSourceFromPlayback);
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
- ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
}
@Test
- public void handleStandby_fromNonActiveSource_noStandby() {
+ public void handleStandby_fromNonActiveSource_previousActiveSourceSet_noStandby() {
+ HdmiCecMessage activeSourceFromPlayback =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_2, 0x2000);
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
mPowerManager.setInteractive(true);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ mHdmiCecLocalDeviceTv.dispatchMessage(activeSourceFromPlayback);
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_2, 0x2000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
- ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isTrue();
}
+
+
+ @Test
+ public void handleStandby_fromNonActiveSource_previousActiveSourceNotSet_Standby() {
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ mPowerManager.setInteractive(true);
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+ .isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ }
+
+ protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
+ MockTvDevice(HdmiControlService service) {
+ super(service);
+ }
+
+ @Override
+ protected int handleActiveSource(HdmiCecMessage message) {
+ setWasActiveSourceSetToConnectedDevice(true);
+ return super.handleActiveSource(message);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 37065fd..02d3b59 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1424,6 +1424,39 @@
@MediumTest
@Test
+ public void testSerialNumberAfterUserRemoval() {
+ final UserInfo user = mUserManager.createUser("Test User", 0);
+ assertThat(user).isNotNull();
+
+ final int userId = user.id;
+ assertThat(mUserManager.getUserSerialNumber(userId))
+ .isEqualTo(user.serialNumber);
+ mUsersToRemove.add(userId);
+ removeUser(userId);
+ int serialNumber = mUserManager.getUserSerialNumber(userId);
+ int timeout = REMOVE_USER_TIMEOUT_SECONDS * 5; // called every 200ms
+
+ // Wait for the user to be removed from memory
+ while(serialNumber > 0 && timeout > 0){
+ sleep(200);
+ timeout--;
+ serialNumber = mUserManager.getUserSerialNumber(userId);
+ }
+ assertThat(serialNumber).isEqualTo(-1);
+ }
+
+
+ private void sleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @MediumTest
+ @Test
public void testMaxUsers() {
int N = UserManager.getMaxSupportedUsers();
int count = mUserManager.getUsers().size();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
index 12ab3e1..a3252f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
@@ -103,8 +103,8 @@
@Test
public void testShouldRefreshActivity_refreshDisabledForActivity() throws Exception {
configureActivityAndDisplay();
- when(mActivity.mLetterboxUiController.shouldRefreshActivityForCameraCompat())
- .thenReturn(false);
+ when(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat()).thenReturn(false);
mActivityRefresher.addEvaluator(mEvaluatorTrue);
mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
@@ -160,8 +160,9 @@
throws Exception {
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .shouldRefreshActivityViaPauseForCameraCompat();
+ doReturn(true)
+ .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
@@ -172,8 +173,9 @@
public void testOnActivityRefreshed_setIsRefreshRequestedToFalse() throws Exception {
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .shouldRefreshActivityViaPauseForCameraCompat();
+ doReturn(true)
+ .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityRefreshed(mActivity);
@@ -186,8 +188,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
@@ -211,9 +213,9 @@
.getTopMostActivity();
spyOn(mActivity.mLetterboxUiController);
- doReturn(true).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
-
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
doReturn(true).when(mActivity).inFreeformWindowingMode();
+ doReturn(true).when(mActivity.mAppCompatController
+ .getAppCompatCameraOverrides()).shouldRefreshActivityForCameraCompat();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index 5f2853a..467050e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -149,6 +149,10 @@
.mLetterboxUiController).shouldApplyUserMinAspectRatioOverride();
}
+ void setShouldCreateCompatDisplayInsets(boolean enabled) {
+ doReturn(enabled).when(mActivityStack.top()).shouldCreateCompatDisplayInsets();
+ }
+
void setShouldApplyUserFullscreenOverride(boolean enabled) {
doReturn(enabled).when(mActivityStack.top()
.mLetterboxUiController).shouldApplyUserFullscreenOverride();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
new file mode 100644
index 0000000..9263b4f
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.testng.Assert;
+
+import java.util.function.Consumer;
+
+/**
+ * Test class for {@link AppCompatCameraOverrides}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:AppCompatCameraOverridesTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class AppCompatCameraOverridesTest extends WindowTestsBase {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(true);
+ });
+ }
+
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyFalseAndOverrideFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(true);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @DisableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA,
+ OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void testShouldRecomputeConfigurationForCameraCompat() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
+ robot.activity().createActivityWithComponentInNewTask();
+ robot.activateCamera(true);
+ robot.activity().setShouldCreateCompatDisplayInsets(false);
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
+ });
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ void runTestScenario(@NonNull Consumer<CameraOverridesRobotTest> consumer) {
+ spyOn(mWm.mLetterboxConfiguration);
+ final CameraOverridesRobotTest robot = new CameraOverridesRobotTest(mWm, mAtm, mSupervisor);
+ consumer.accept(robot);
+ }
+
+ private static class CameraOverridesRobotTest extends AppCompatRobotBase {
+
+ CameraOverridesRobotTest(@NonNull WindowManagerService wm,
+ @NonNull ActivityTaskManagerService atm,
+ @NonNull ActivityTaskSupervisor supervisor) {
+ super(wm, atm, supervisor);
+ }
+
+ void activateCamera(boolean isCameraActive) {
+ doReturn(isCameraActive).when(activity().top()).isCameraActive();
+ }
+
+ void checkShouldRefreshActivityForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat(), expected);
+ }
+
+ void checkShouldRefreshActivityViaPauseForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat(), expected);
+ }
+
+ void checkShouldForceRotateForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat(), expected);
+ }
+
+ void checkShouldApplyFreeformTreatmentForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldApplyFreeformTreatmentForCameraCompat(), expected);
+ }
+
+ private AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return activity().top().mAppCompatController.getAppCompatCameraOverrides();
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
new file mode 100644
index 0000000..4116313
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+/**
+ * Test class for {@link AppCompatCameraPolicy}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:AppCompatCameraPolicyTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class AppCompatCameraPolicyTest extends WindowTestsBase {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraCompatIfNeeded_allDisabledNoRecompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ false);
+
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraCompatIfNeeded_cameraEnabledRecompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeeded_recompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeededWithCamera_recompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ true);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ void runTestScenario(@NonNull Consumer<CameraPolicyRobotTest> consumer) {
+ spyOn(mWm.mLetterboxConfiguration);
+ final CameraPolicyRobotTest robot = new CameraPolicyRobotTest(mWm, mAtm, mSupervisor);
+ consumer.accept(robot);
+ }
+
+ private static class CameraPolicyRobotTest extends AppCompatRobotBase {
+
+ private final WindowManagerService mWm;
+
+ CameraPolicyRobotTest(@NonNull WindowManagerService wm,
+ @NonNull ActivityTaskManagerService atm,
+ @NonNull ActivityTaskSupervisor supervisor) {
+ super(wm, atm, supervisor);
+ mWm = wm;
+ spyOn(mWm);
+ }
+
+ void activateCamera(boolean isCameraActive) {
+ doReturn(isCameraActive).when(activity().top()).isCameraActive();
+ }
+
+ void recomputeConfigurationForCameraCompatIfNeeded() {
+ getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
+ }
+
+ void checkRecomputeConfigurationInvoked(boolean invoked) {
+ if (invoked) {
+ verify(activity().top()).recomputeConfiguration();
+ } else {
+ verify(activity().top(), never()).recomputeConfiguration();
+ }
+ }
+
+ private AppCompatCameraPolicy getAppCompatCameraPolicy() {
+ return activity().top().mAppCompatController.getAppCompatCameraPolicy();
+ }
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
index 2ef77f6..e1da913 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
@@ -61,4 +61,11 @@
void enableUserAppAspectRatioSettings(boolean enabled) {
doReturn(enabled).when(mLetterboxConfiguration).isUserAppAspectRatioSettingsEnabled();
}
+
+ void enableCameraCompatSplitScreenAspectRatio(boolean enabled) {
+ doReturn(enabled).when(mLetterboxConfiguration)
+ .isCameraCompatSplitScreenAspectRatioEnabled();
+ }
+
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index b3f1502..564c29f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -245,8 +245,8 @@
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity);
@@ -271,7 +271,7 @@
public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -305,6 +305,7 @@
.build();
spyOn(mActivity.mLetterboxUiController);
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
spyOn(mActivity.info);
doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean());
@@ -315,12 +316,14 @@
private void assertInCameraCompatMode() {
assertNotEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mLetterboxUiController.getFreeformCameraCompatMode());
+ mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode());
}
private void assertNotInCameraCompatMode() {
assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mLetterboxUiController.getFreeformCameraCompatMode());
+ mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode());
}
private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -329,8 +332,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index c65371f..d7814ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -266,7 +266,7 @@
public void testTreatmentDisabledPerApp_noForceRotationOrRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(mActivity.mLetterboxUiController)
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldForceRotateForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -468,8 +468,8 @@
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true);
@@ -494,8 +494,9 @@
public void testOnActivityConfigurationChanging_displayRotationNotChanging_noRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(mActivity.mLetterboxUiController)
- .isCameraCompatSplitScreenAspectRatioAllowed();
+ doReturn(false).when(mActivity
+ .mAppCompatController.getAppCompatCameraOverrides())
+ .isCameraCompatSplitScreenAspectRatioAllowed();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ false);
@@ -507,7 +508,7 @@
public void testOnActivityConfigurationChanging_splitScreenAspectRatioAllowed_refresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.isCameraCompatSplitScreenAspectRatioAllowed();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -533,7 +534,7 @@
public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -597,6 +598,7 @@
spyOn(mActivity.mAtmService.getLifecycleManager());
spyOn(mActivity.mLetterboxUiController);
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean());
doReturn(naturalOrientation).when(mDisplayContent).getNaturalOrientation();
@@ -608,8 +610,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index bdd45c6..74e2d44 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -18,10 +18,6 @@
import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
@@ -31,9 +27,6 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
@@ -45,7 +38,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -54,8 +46,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -129,200 +119,7 @@
mController = new LetterboxUiController(mWm, mActivity);
}
- // shouldRefreshActivityForCameraCompat
- @Test
- public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
- public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
- public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldRefreshActivityForCameraCompat());
- }
-
- // shouldRefreshActivityViaPauseForCameraCompat
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsFalseAndOverride_returnFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- // shouldForceRotateForCameraCompat
-
- @Test
- public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
- public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
- public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldForceRotateForCameraCompat());
- }
-
- // shouldApplyFreeformTreatmentForCameraCompat
-
- @Test
- public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
- mSetFlagsRule.disableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
- public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
- public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse()
- throws Exception {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue()
- throws Exception {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
@Test
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
@@ -641,39 +438,6 @@
assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
}
- @Test
- public void testRecomputeConfigurationForCameraCompatIfNeeded() {
- spyOn(mController);
- doReturn(false).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- doReturn(false).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- doReturn(false).when(mController).shouldOverrideMinAspectRatioForCamera();
- clearInvocations(mActivity);
-
- mController.recomputeConfigurationForCameraCompatIfNeeded();
-
- verify(mActivity, never()).recomputeConfiguration();
-
- // isOverrideOrientationOnlyForCameraEnabled
- doReturn(true).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
-
- // isCameraCompatSplitScreenAspectRatioAllowed
- doReturn(false).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- doReturn(true).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
-
- // shouldOverrideMinAspectRatioForCamera
- doReturn(false).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- doReturn(true).when(mController).shouldOverrideMinAspectRatioForCamera();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
- }
-
private void prepareActivityForShouldApplyUserMinAspectRatioOverride(
boolean orientationRequest) {
spyOn(mController);
@@ -875,7 +639,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertTrue(mController.shouldOverrideMinAspectRatioForCamera());
+ assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -886,7 +651,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertTrue(mController.shouldOverrideMinAspectRatioForCamera());
+ assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -897,7 +663,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -908,7 +675,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -917,7 +685,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -927,7 +696,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -938,7 +708,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index ef0aa9e..4bc87b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -2013,7 +2013,7 @@
public void getTaskInfoPropagatesCameraCompatMode() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopMostActivity();
- activity.mLetterboxUiController
+ activity.mAppCompatController.getAppCompatCameraOverrides()
.setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT);
assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT,