summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt4
-rw-r--r--core/java/android/app/ApplicationStartInfo.java26
-rw-r--r--core/java/android/app/WindowConfiguration.java6
-rw-r--r--core/java/android/app/activity_manager.aconfig20
-rw-r--r--core/java/android/view/InsetsController.java12
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/inputmethod/ImeTracker.java4
-rw-r--r--core/java/com/android/internal/jank/Cuj.java18
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt13
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt6
-rw-r--r--media/java/android/media/MediaCodecInfo.java15
-rw-r--r--media/java/android/media/MediaRecorder.java2
-rw-r--r--packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java48
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java11
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java7
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt94
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt28
-rw-r--r--packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java59
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java117
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java4
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java31
-rw-r--r--services/core/java/com/android/server/wm/AbsAppSnapshotController.java18
-rw-r--r--services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java9
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java43
-rw-r--r--services/core/java/com/android/server/wm/SnapshotPersistQueue.java81
-rw-r--r--services/core/java/com/android/server/wm/Task.java80
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java13
43 files changed, 800 insertions, 290 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 216bbab882a9..bba21f418e41 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24820,7 +24820,7 @@ package android.media {
method public android.view.Surface getSurface();
method public boolean isPrivacySensitive();
method public void pause() throws java.lang.IllegalStateException;
- method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
+ method @RequiresPermission(value=android.Manifest.permission.RECORD_AUDIO, conditional=true) public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
method public void release();
method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
@@ -24861,7 +24861,7 @@ package android.media {
method public void setVideoProfile(@NonNull android.media.EncoderProfiles.VideoProfile);
method public void setVideoSize(int, int) throws java.lang.IllegalStateException;
method public void setVideoSource(int) throws java.lang.IllegalStateException;
- method public void start() throws java.lang.IllegalStateException;
+ method @RequiresPermission(value=android.Manifest.permission.RECORD_AUDIO, conditional=true) public void start() throws java.lang.IllegalStateException;
method public void stop() throws java.lang.IllegalStateException;
method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index 2e8031dd22fe..2559bd036039 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -231,9 +231,9 @@ public final class ApplicationStartInfo implements Parcelable {
public static final int START_COMPONENT_OTHER = 5;
/**
- * @see #getMonoticCreationTimeMs
+ * @see #getMonotonicCreationTimeMs
*/
- private long mMonoticCreationTimeMs;
+ private long mMonotonicCreationTimeMs;
/**
* @see #getStartupState
@@ -545,8 +545,8 @@ public final class ApplicationStartInfo implements Parcelable {
*
* @hide
*/
- public long getMonoticCreationTimeMs() {
- return mMonoticCreationTimeMs;
+ public long getMonotonicCreationTimeMs() {
+ return mMonotonicCreationTimeMs;
}
/**
@@ -751,14 +751,14 @@ public final class ApplicationStartInfo implements Parcelable {
dest.writeParcelable(mStartIntent, flags);
dest.writeInt(mLaunchMode);
dest.writeBoolean(mWasForceStopped);
- dest.writeLong(mMonoticCreationTimeMs);
+ dest.writeLong(mMonotonicCreationTimeMs);
dest.writeInt(mStartComponent);
}
// LINT.ThenChange(:read_parcel)
/** @hide */
public ApplicationStartInfo(long monotonicCreationTimeMs) {
- mMonoticCreationTimeMs = monotonicCreationTimeMs;
+ mMonotonicCreationTimeMs = monotonicCreationTimeMs;
}
/** @hide */
@@ -776,7 +776,7 @@ public final class ApplicationStartInfo implements Parcelable {
mStartIntent = other.mStartIntent;
mLaunchMode = other.mLaunchMode;
mWasForceStopped = other.mWasForceStopped;
- mMonoticCreationTimeMs = other.mMonoticCreationTimeMs;
+ mMonotonicCreationTimeMs = other.mMonotonicCreationTimeMs;
mStartComponent = other.mStartComponent;
}
@@ -803,7 +803,7 @@ public final class ApplicationStartInfo implements Parcelable {
in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
mLaunchMode = in.readInt();
mWasForceStopped = in.readBoolean();
- mMonoticCreationTimeMs = in.readLong();
+ mMonotonicCreationTimeMs = in.readLong();
mStartComponent = in.readInt();
}
// LINT.ThenChange(:write_parcel)
@@ -887,7 +887,7 @@ public final class ApplicationStartInfo implements Parcelable {
}
proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode);
proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped);
- proto.write(ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS, mMonoticCreationTimeMs);
+ proto.write(ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS, mMonotonicCreationTimeMs);
proto.write(ApplicationStartInfoProto.START_COMPONENT, mStartComponent);
proto.end(token);
}
@@ -980,7 +980,7 @@ public final class ApplicationStartInfo implements Parcelable {
ApplicationStartInfoProto.WAS_FORCE_STOPPED);
break;
case (int) ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS:
- mMonoticCreationTimeMs = proto.readLong(
+ mMonotonicCreationTimeMs = proto.readLong(
ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS);
break;
case (int) ApplicationStartInfoProto.START_COMPONENT:
@@ -999,7 +999,7 @@ public final class ApplicationStartInfo implements Parcelable {
sb.append(prefix)
.append("ApplicationStartInfo ").append(seqSuffix).append(':')
.append('\n')
- .append(" monotonicCreationTimeMs=").append(mMonoticCreationTimeMs)
+ .append(" monotonicCreationTimeMs=").append(mMonotonicCreationTimeMs)
.append('\n')
.append(" pid=").append(mPid)
.append(" realUid=").append(mRealUid)
@@ -1094,7 +1094,7 @@ public final class ApplicationStartInfo implements Parcelable {
&& TextUtils.equals(mProcessName, o.mProcessName)
&& timestampsEquals(o)
&& mWasForceStopped == o.mWasForceStopped
- && mMonoticCreationTimeMs == o.mMonoticCreationTimeMs
+ && mMonotonicCreationTimeMs == o.mMonotonicCreationTimeMs
&& mStartComponent == o.mStartComponent;
}
@@ -1102,7 +1102,7 @@ public final class ApplicationStartInfo implements Parcelable {
public int hashCode() {
return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState,
mStartType, mLaunchMode, mPackageName, mProcessName, mStartupTimestampsNs,
- mMonoticCreationTimeMs, mStartComponent);
+ mMonotonicCreationTimeMs, mStartComponent);
}
private boolean timestampsEquals(@NonNull ApplicationStartInfo other) {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index c6d0f61b529e..8c99bd8e2ed9 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -790,12 +790,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
|| mWindowingMode == WINDOWING_MODE_MULTI_WINDOW;
}
- /** Returns true if the task bounds should persist across power cycles.
- * @hide */
- public boolean persistTaskBounds() {
- return mWindowingMode == WINDOWING_MODE_FREEFORM;
- }
-
/**
* Returns true if the tasks associated with this window configuration are floating.
* Floating tasks are laid out differently as they are allowed to extend past the display bounds
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index e431426d5d09..29c84ee00b44 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -170,3 +170,23 @@ flag {
description: "Holdback study for jank_perceptible_narrow"
bug: "304837972"
}
+
+flag {
+ namespace: "system_performance"
+ name: "app_start_info_cleanup_old_records"
+ description: "Cleanup old records to reduce size of in memory store."
+ bug: "384539178"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "system_performance"
+ name: "app_start_info_keep_records_sorted"
+ description: "Ensure records are kept sorted to avoid extra work"
+ bug: "384539178"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 6b7b81887706..7e9dfe6d972a 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1030,10 +1030,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
handlePendingControlRequest(statsToken);
} else {
if (showTypes[0] != 0) {
+ if ((showTypes[0] & ime()) != 0) {
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_CLIENT_ON_CONTROLS_CHANGED);
+ }
applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
false /* skipsCallbacks */, statsToken);
}
if (hideTypes[0] != 0) {
+ if ((hideTypes[0] & ime()) != 0) {
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_CLIENT_ON_CONTROLS_CHANGED);
+ }
applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
// The animation of hiding transient types shouldn't be detected by the
// app. Otherwise, it might be able to react to the callbacks and cause
@@ -1041,6 +1049,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
(hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
statsToken);
}
+ if ((showTypes[0] & ime()) == 0 && (hideTypes[0] & ime()) == 0) {
+ ImeTracker.forLogging().onCancelled(statsToken,
+ ImeTracker.PHASE_CLIENT_ON_CONTROLS_CHANGED);
+ }
}
} else {
if (showTypes[0] != 0) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1b57b0045537..94e9aa709369 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1070,9 +1070,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
if (mSurfacePackage != null) {
- mSurfaceControlViewHostParent.detach();
mEmbeddedWindowParams.clear();
if (releaseSurfacePackage) {
+ mSurfaceControlViewHostParent.detach();
mSurfacePackage.release();
mSurfacePackage = null;
}
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 5dadf32d2a36..b1ba8b32d2f4 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -231,6 +231,7 @@ public interface ImeTracker {
PHASE_WM_WINDOW_ANIMATING_TYPES_CHANGED,
PHASE_WM_NOTIFY_HIDE_ANIMATION_FINISHED,
PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES,
+ PHASE_CLIENT_ON_CONTROLS_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
@interface Phase {}
@@ -469,6 +470,9 @@ public interface ImeTracker {
/** The control target reported its animatingTypes back to WindowManagerService. */
int PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES =
ImeProtoEnums.PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES;
+ /** InsetsController received a control for the IME. */
+ int PHASE_CLIENT_ON_CONTROLS_CHANGED =
+ ImeProtoEnums.PHASE_CLIENT_ON_CONTROLS_CHANGED;
/**
* Called when an IME request is started.
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index e125e258c596..c25f6b1dcacb 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -322,8 +322,18 @@ public class Cuj {
*/
public static final int CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY = 129;
+ /**
+ * Track the animation of an ongoing call app back into its status bar chip (displaying the call
+ * icon and timer) when returning Home.
+ *
+ * <p>Tracking starts when the RemoteTransition registered to handle the transition from the app
+ * to Home is sent the onAnimationStart() signal and start the animation. Tracking ends when
+ * the animation is fully settled and the transition is complete.</p>
+ */
+ public static final int CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP = 130;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP;
/** @hide */
@IntDef({
@@ -444,7 +454,8 @@ public class Cuj {
CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND,
CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK,
CUJ_DEFAULT_TASK_TO_TASK_ANIMATION,
- CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY
+ CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY,
+ CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -576,6 +587,7 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WORK_UTILITY_VIEW_SHRINK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DEFAULT_TASK_TO_TASK_ANIMATION] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DEFAULT_TASK_TO_TASK_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_RETURN_TO_CALL_CHIP;
}
private Cuj() {
@@ -830,6 +842,8 @@ public class Cuj {
return "DEFAULT_TASK_TO_TASK_ANIMATION";
case CUJ_DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY:
return "DESKTOP_MODE_MOVE_WINDOW_TO_DISPLAY";
+ case CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP:
+ return "STATUS_BAR_APP_RETURN_TO_CALL_CHIP";
}
return "UNKNOWN";
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
index 25b9f8ccc6ae..f68afea92850 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.shared;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.IntDef;
import android.app.ActivityManager.RecentTaskInfo;
@@ -65,6 +66,11 @@ public class GroupedTaskInfo implements Parcelable {
private final int mDeskId;
/**
+ * The ID of the display that desk with [mDeskId] is in.
+ */
+ private final int mDeskDisplayId;
+
+ /**
* The type of this particular task info, can be one of TYPE_FULLSCREEN, TYPE_SPLIT or
* TYPE_DESK.
*/
@@ -109,17 +115,19 @@ public class GroupedTaskInfo implements Parcelable {
* Create new for a stack of fullscreen tasks
*/
public static GroupedTaskInfo forFullscreenTasks(@NonNull TaskInfo task) {
- return new GroupedTaskInfo(/* deskId = */ -1, List.of(task), null, TYPE_FULLSCREEN,
- /* minimizedFreeformTaskIds = */ null);
+ return new GroupedTaskInfo(/* deskId = */ -1, /* displayId = */ INVALID_DISPLAY,
+ List.of(task), null,
+ TYPE_FULLSCREEN, /* minimizedFreeformTaskIds = */ null);
}
/**
* Create new for a pair of tasks in split screen
*/
public static GroupedTaskInfo forSplitTasks(@NonNull TaskInfo task1,
- @NonNull TaskInfo task2, @NonNull SplitBounds splitBounds) {
- return new GroupedTaskInfo(/* deskId = */ -1, List.of(task1, task2), splitBounds,
- TYPE_SPLIT, /* minimizedFreeformTaskIds = */ null);
+ @NonNull TaskInfo task2, @NonNull SplitBounds splitBounds) {
+ return new GroupedTaskInfo(/* deskId = */ -1, /* displayId = */ INVALID_DISPLAY,
+ List.of(task1, task2),
+ splitBounds, TYPE_SPLIT, /* minimizedFreeformTaskIds = */ null);
}
/**
@@ -127,9 +135,11 @@ public class GroupedTaskInfo implements Parcelable {
*/
public static GroupedTaskInfo forDeskTasks(
int deskId,
+ int deskDisplayId,
@NonNull List<TaskInfo> tasks,
@NonNull Set<Integer> minimizedFreeformTaskIds) {
- return new GroupedTaskInfo(deskId, tasks, /* splitBounds = */ null, TYPE_DESK,
+ return new GroupedTaskInfo(deskId, deskDisplayId, tasks, /* splitBounds = */ null,
+ TYPE_DESK,
minimizedFreeformTaskIds.stream().mapToInt(i -> i).toArray());
}
@@ -149,11 +159,13 @@ public class GroupedTaskInfo implements Parcelable {
private GroupedTaskInfo(
int deskId,
+ int deskDisplayId,
@NonNull List<TaskInfo> tasks,
@Nullable SplitBounds splitBounds,
@GroupType int type,
@Nullable int[] minimizedFreeformTaskIds) {
mDeskId = deskId;
+ mDeskDisplayId = deskDisplayId;
mTasks = tasks;
mGroupedTasks = null;
mSplitBounds = splitBounds;
@@ -164,6 +176,7 @@ public class GroupedTaskInfo implements Parcelable {
private GroupedTaskInfo(@NonNull List<GroupedTaskInfo> groupedTasks) {
mDeskId = -1;
+ mDeskDisplayId = INVALID_DISPLAY;
mTasks = null;
mGroupedTasks = groupedTasks;
mSplitBounds = null;
@@ -185,6 +198,7 @@ public class GroupedTaskInfo implements Parcelable {
protected GroupedTaskInfo(@NonNull Parcel parcel) {
mDeskId = parcel.readInt();
+ mDeskDisplayId = parcel.readInt();
mTasks = new ArrayList();
final int numTasks = parcel.readInt();
for (int i = 0; i < numTasks; i++) {
@@ -295,6 +309,16 @@ public class GroupedTaskInfo implements Parcelable {
}
/**
+ * Returns the ID of the display that hosts the desk represented by [mDeskId].
+ */
+ public int getDeskDisplayId() {
+ if (mType != TYPE_DESK) {
+ throw new IllegalStateException("No display ID for non desktop task");
+ }
+ return mDeskDisplayId;
+ }
+
+ /**
* Get type of this recents entry. One of {@link GroupType}.
* Note: This is deprecated, callers should use `isBaseType()` and not make assumptions about
* specific group types
@@ -323,6 +347,7 @@ public class GroupedTaskInfo implements Parcelable {
}
GroupedTaskInfo other = (GroupedTaskInfo) obj;
return mDeskId == other.mDeskId
+ && mDeskDisplayId == other.mDeskDisplayId
&& mType == other.mType
&& Objects.equals(mTasks, other.mTasks)
&& Objects.equals(mGroupedTasks, other.mGroupedTasks)
@@ -332,7 +357,7 @@ public class GroupedTaskInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mDeskId, mType, mTasks, mGroupedTasks, mSplitBounds,
+ return Objects.hash(mDeskId, mDeskDisplayId, mType, mTasks, mGroupedTasks, mSplitBounds,
Arrays.hashCode(mMinimizedTaskIds));
}
@@ -345,6 +370,7 @@ public class GroupedTaskInfo implements Parcelable {
.collect(Collectors.joining(",\n\t", "[\n\t", "\n]")));
} else {
taskString.append("Desk ID= ").append(mDeskId).append(", ");
+ taskString.append("Desk Display ID=").append(mDeskDisplayId).append(", ");
taskString.append("Tasks=" + mTasks.stream()
.map(taskInfo -> getTaskInfoDumpString(taskInfo))
.collect(Collectors.joining(", ", "[", "]")));
@@ -377,6 +403,7 @@ public class GroupedTaskInfo implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mDeskId);
+ parcel.writeInt(mDeskDisplayId);
// We don't use the parcel list methods because we want to only write the TaskInfo state
// and not the subclasses (Recents/RunningTaskInfo) whose fields are all deprecated
final int tasksSize = mTasks != null ? mTasks.size() : 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 7f8cfaeb9c03..5e36a102a438 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -332,7 +332,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@Override
public void onThresholdCrossed() {
- BackAnimationController.this.onThresholdCrossed();
+ if (predictiveBackDelayWmTransition()) {
+ mShellExecutor.execute(BackAnimationController.this::onThresholdCrossed);
+ } else {
+ BackAnimationController.this.onThresholdCrossed();
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index bb5b5cec1b4a..382fa9640ff9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -536,17 +536,20 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
/**
- * Represents a desk whose ID is `mDeskId` and contains the tasks in `mDeskTasks`. Some of these
- * tasks are minimized and their IDs are contained in the `mMinimizedDeskTasks` set.
+ * Represents a desk whose ID is `mDeskId` inside the display with `mDisplayId` and contains
+ * the tasks in `mDeskTasks`. Some of these tasks are minimized and their IDs are contained
+ * in the `mMinimizedDeskTasks` set.
*/
private static class Desk {
final int mDeskId;
+ final int mDisplayId;
boolean mHasVisibleTasks = false;
final ArrayList<TaskInfo> mDeskTasks = new ArrayList<>();
final Set<Integer> mMinimizedDeskTasks = new HashSet<>();
- Desk(int deskId) {
+ Desk(int deskId, int displayId) {
mDeskId = deskId;
+ mDisplayId = displayId;
}
void addTask(TaskInfo taskInfo, boolean isMinimized, boolean isVisible) {
@@ -562,7 +565,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
GroupedTaskInfo createDeskTaskInfo() {
- return GroupedTaskInfo.forDeskTasks(mDeskId, mDeskTasks, mMinimizedDeskTasks);
+ return GroupedTaskInfo.forDeskTasks(mDeskId, mDisplayId, mDeskTasks,
+ mMinimizedDeskTasks);
}
}
@@ -601,7 +605,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private Desk getOrCreateDesk(int deskId) {
var desk = mTmpDesks.get(deskId);
if (desk == null) {
- desk = new Desk(deskId);
+ desk = new Desk(deskId,
+ mDesktopUserRepositories.get().getCurrent().getDisplayForDesk(deskId));
mTmpDesks.put(deskId, desk);
}
return desk;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index 23dfb41d52c1..cca982142a3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -153,7 +153,6 @@ public class HomeTransitionObserver implements TransitionObserver,
return;
}
mPendingStartDragTransition = null;
- if (aborted) return;
if (mPendingHomeVisibilityUpdate != null) {
notifyHomeVisibilityChanged(mPendingHomeVisibilityUpdate);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
index eb324f74ca82..238242792782 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
@@ -278,13 +278,16 @@ class MultiDisplayVeiledResizeTaskPositioner(
currentDisplayLayout,
)
)
-
- multiDisplayDragMoveIndicatorController.onDragEnd(
- desktopWindowDecoration.mTaskInfo.taskId,
- transactionSupplier,
- )
}
+ // Call the MultiDisplayDragMoveIndicatorController to clear any active indicator
+ // surfaces. This is necessary even if the drag ended on the same display, as surfaces
+ // may have been created for other displays during the drag.
+ multiDisplayDragMoveIndicatorController.onDragEnd(
+ desktopWindowDecoration.mTaskInfo.taskId,
+ transactionSupplier,
+ )
+
interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
index 75f6bda4d750..4e8812d34ef4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
@@ -21,6 +21,7 @@ import android.app.TaskInfo
import android.graphics.Rect
import android.os.Parcel
import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
import android.window.IWindowContainerToken
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
@@ -281,7 +282,8 @@ class GroupedTaskInfoTest : ShellTestCase() {
val task2 = createTaskInfo(id = 2)
val taskInfo = GroupedTaskInfo.forDeskTasks(
- /* deskId = */ 500, listOf(task1, task2), setOf())
+ /* deskId = */ 500, DEFAULT_DISPLAY, listOf(task1, task2), setOf()
+ )
assertThat(taskInfo.deskId).isEqualTo(500)
assertThat(taskInfo.getTaskById(1)).isEqualTo(task1)
@@ -335,6 +337,7 @@ class GroupedTaskInfoTest : ShellTestCase() {
): GroupedTaskInfo {
return GroupedTaskInfo.forDeskTasks(
deskId,
+ DEFAULT_DISPLAY,
freeformTaskIds.map { createTaskInfo(it) }.toList(),
minimizedTaskIds.toSet())
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index a122c3820dcb..55bff09e0ae2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -222,7 +222,7 @@ public class HomeTransitionObserverTest extends ShellTestCase {
@Test
@EnableFlags({FLAG_ENABLE_DRAG_TO_DESKTOP_INCOMING_TRANSITIONS_BUGFIX})
- public void startDragToDesktopAborted_doesNotTriggerCallback() throws RemoteException {
+ public void startDragToDesktopAborted_triggersCallback() throws RemoteException {
TransitionInfo info = mock(TransitionInfo.class);
TransitionInfo.Change change = mock(TransitionInfo.Change.class);
ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
@@ -239,7 +239,7 @@ public class HomeTransitionObserverTest extends ShellTestCase {
mHomeTransitionObserver.onTransitionFinished(transition, /* aborted= */ true);
- verify(mListener, never()).onHomeVisibilityChanged(/* isVisible= */ anyBoolean());
+ verify(mListener).onHomeVisibilityChanged(/* isVisible= */ true);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
index 0798613ed632..24a46aacde15 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
@@ -63,6 +63,7 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoInteractions
import org.mockito.Mockito.`when`
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -210,6 +211,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
eq(taskPositioner),
)
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verifyNoInteractions(mockMultiDisplayDragMoveIndicatorController)
}
@Test
@@ -248,6 +250,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(mockDesktopWindowDecoration, never()).showResizeVeil(any())
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
Assert.assertEquals(rectAfterEnd, endBounds)
}
@@ -268,6 +271,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(spyDisplayLayout0, never()).localPxToGlobalDp(any(), any())
verify(spyDisplayLayout0, never()).globalDpToLocalPx(any(), any())
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
}
@Test
@@ -290,6 +294,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
verify(mockDesktopWindowDecoration, never()).showResizeVeil(any())
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ verify(mockMultiDisplayDragMoveIndicatorController).onDragEnd(eq(TASK_ID), any())
Assert.assertEquals(rectAfterEnd, endBounds)
}
@@ -346,6 +351,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
},
eq(taskPositioner),
)
+ verifyNoInteractions(mockMultiDisplayDragMoveIndicatorController)
}
@Test
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index f3b21bfdaa3c..3b560b7a880e 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -219,13 +219,14 @@ public final class MediaCodecInfo {
private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
- private static final class LazyHolder {
- private static final Range<Integer> SIZE_RANGE = Process.is64Bit()
- ? Range.create(1, 32768)
- : Range.create(1, MediaProperties.resolution_limit_32bit().orElse(4096));
- }
- private static Range<Integer> getSizeRange() {
- return LazyHolder.SIZE_RANGE;
+ private static Range<Integer> SIZE_RANGE;
+ private static synchronized Range<Integer> getSizeRange() {
+ if (SIZE_RANGE == null) {
+ SIZE_RANGE = Process.is64Bit()
+ ? Range.create(1, 32768)
+ : Range.create(1, MediaProperties.resolution_limit_32bit().orElse(4096));
+ }
+ return SIZE_RANGE;
}
// found stuff that is not supported by framework (=> this should not happen)
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 7af78b81cda5..03bcc6afc1b7 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1299,6 +1299,7 @@ public class MediaRecorder implements AudioRouting,
* start() or before setOutputFormat().
* @throws IOException if prepare fails otherwise.
*/
+ @RequiresPermission(value = android.Manifest.permission.RECORD_AUDIO, conditional = true)
public void prepare() throws IllegalStateException, IOException
{
if (mPath != null) {
@@ -1337,6 +1338,7 @@ public class MediaRecorder implements AudioRouting,
* @throws IllegalStateException if it is called before
* prepare() or when the camera is already in use by another app.
*/
+ @RequiresPermission(value = android.Manifest.permission.RECORD_AUDIO, conditional = true)
public native void start() throws IllegalStateException;
/**
diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
index be711accd542..89e5372b530e 100644
--- a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
+++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
@@ -27,6 +27,7 @@ import android.widget.Button;
import android.widget.LinearLayout;
import androidx.annotation.GravityInt;
+import androidx.annotation.IntDef;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -34,21 +35,46 @@ import com.android.settingslib.widget.preference.button.R;
import com.google.android.material.button.MaterialButton;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A preference handled a button
*/
public class ButtonPreference extends Preference implements GroupSectionDividerMixin {
+ public static final int TYPE_FILLED = 0;
+ public static final int TYPE_TONAL = 1;
+ public static final int TYPE_OUTLINE = 2;
+
+ @IntDef({TYPE_FILLED, TYPE_TONAL, TYPE_OUTLINE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {
+ }
+
+ public static final int SIZE_NORMAL = 0;
+ public static final int SIZE_LARGE = 1;
+ public static final int SIZE_EXTRA_LARGE = 2;
+
+ @IntDef({SIZE_NORMAL, SIZE_LARGE, SIZE_EXTRA_LARGE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Size {
+ }
+
enum ButtonStyle {
- FILLED_NORMAL(0, 0, R.layout.settingslib_expressive_button_filled),
- FILLED_LARGE(0, 1, R.layout.settingslib_expressive_button_filled_large),
- FILLED_EXTRA(0, 2, R.layout.settingslib_expressive_button_filled_extra),
- TONAL_NORMAL(1, 0, R.layout.settingslib_expressive_button_tonal),
- TONAL_LARGE(1, 1, R.layout.settingslib_expressive_button_tonal_large),
- TONAL_EXTRA(1, 2, R.layout.settingslib_expressive_button_tonal_extra),
- OUTLINE_NORMAL(2, 0, R.layout.settingslib_expressive_button_outline),
- OUTLINE_LARGE(2, 1, R.layout.settingslib_expressive_button_outline_large),
- OUTLINE_EXTRA(2, 2, R.layout.settingslib_expressive_button_outline_extra);
+ FILLED_NORMAL(TYPE_FILLED, SIZE_NORMAL, R.layout.settingslib_expressive_button_filled),
+ FILLED_LARGE(TYPE_FILLED, SIZE_LARGE, R.layout.settingslib_expressive_button_filled_large),
+ FILLED_EXTRA(TYPE_FILLED, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_filled_extra),
+ TONAL_NORMAL(TYPE_TONAL, SIZE_NORMAL, R.layout.settingslib_expressive_button_tonal),
+ TONAL_LARGE(TYPE_TONAL, SIZE_LARGE, R.layout.settingslib_expressive_button_tonal_large),
+ TONAL_EXTRA(TYPE_TONAL, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_tonal_extra),
+ OUTLINE_NORMAL(TYPE_OUTLINE, SIZE_NORMAL, R.layout.settingslib_expressive_button_outline),
+ OUTLINE_LARGE(TYPE_OUTLINE, SIZE_LARGE,
+ R.layout.settingslib_expressive_button_outline_large),
+ OUTLINE_EXTRA(TYPE_OUTLINE, SIZE_EXTRA_LARGE,
+ R.layout.settingslib_expressive_button_outline_extra);
private final int mType;
private final int mSize;
@@ -60,7 +86,7 @@ public class ButtonPreference extends Preference implements GroupSectionDividerM
this.mLayoutId = layoutId;
}
- static int getLayoutId(int type, int size) {
+ static int getLayoutId(@Type int type, @Size int size) {
for (ButtonStyle style : values()) {
if (style.mType == type && style.mSize == size) {
return style.mLayoutId;
@@ -266,7 +292,7 @@ public class ButtonPreference extends Preference implements GroupSectionDividerM
* <li>2: extra large</li>
* </ul>
*/
- public void setButtonStyle(int type, int size) {
+ public void setButtonStyle(@Type int type, @Size int size) {
int layoutId = ButtonStyle.getLayoutId(type, size);
setLayoutResource(layoutId);
notifyChanged();
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 7f4bebcf4a62..335526632383 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -46,6 +46,8 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
@@ -326,6 +328,15 @@ public abstract class Tile implements Parcelable {
return false;
}
+ /** Returns the icon color scheme. */
+ @Nullable
+ public String getIconColorScheme(@NonNull Context context) {
+ ensureMetadataNotStale(context);
+ return mMetaData != null
+ ? mMetaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_COLOR_SCHEME, null)
+ : null;
+ }
+
/** Whether the {@link Activity} should be launched in a separate task. */
public boolean isNewTask() {
if (mMetaData != null && mMetaData.containsKey(META_DATA_NEW_TASK)) {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index ac0b9b45aba6..d62ed2f60ed0 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -135,6 +135,13 @@ public class TileUtils {
public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon";
/**
+ * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the icon
+ * color scheme. Only available for preferences on the homepage.
+ */
+ public static final String META_DATA_PREFERENCE_ICON_COLOR_SCHEME =
+ "com.android.settings.icon_color_scheme";
+
+ /**
* Name of the meta-data item that should be set in the AndroidManifest.xml
* to specify the icon background color. The value may or may not be used by Settings app.
*/
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
index 84370ed4d2c7..6fb3679dfb7c 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
@@ -43,7 +43,7 @@ fun PlatformTheme(isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Compos
val context = LocalContext.current
val colorScheme = remember(context, isDarkTheme) { platformColorScheme(isDarkTheme, context) }
- val androidColorScheme = remember(context) { AndroidColorScheme(context) }
+ val androidColorScheme = remember(context, isDarkTheme) { AndroidColorScheme(context) }
val typefaceNames = remember(context) { TypefaceNames.get(context) }
val typefaceTokens = remember(typefaceNames) { TypefaceTokens(typefaceNames) }
val typography =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 859137507bbf..358635e2400c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -80,17 +80,18 @@ class DisplayRepositoryTest : SysuiTestCase() {
testScope.backgroundScope,
UnconfinedTestDispatcher(),
)
- DisplayRepositoryImpl(
+ val displaysWithDecorRepository =
+ DisplaysWithDecorationsRepositoryImpl(
commandQueue,
windowManager,
testScope.backgroundScope,
displayRepositoryFromLib,
)
- .also {
- verify(displayManager, never()).registerDisplayListener(any(), any())
- // It needs to be called, just once, for the initial value.
- verify(displayManager).getDisplays()
- }
+ DisplayRepositoryImpl(displayRepositoryFromLib, displaysWithDecorRepository).also {
+ verify(displayManager, never()).registerDisplayListener(any(), any())
+ // It needs to be called, just once, for the initial value.
+ verify(displayManager).getDisplays()
+ }
}
@Before
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
index 28b9e733be94..bf49d92dd2bd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
@@ -44,9 +44,10 @@ class PerDisplayInstanceRepositoryImplTest : SysuiTestCase() {
private val fakeDisplayRepository = kosmos.displayRepository
private val fakePerDisplayInstanceProviderWithTeardown =
kosmos.fakePerDisplayInstanceProviderWithTeardown
+ private val lifecycleManager = kosmos.fakeDisplayInstanceLifecycleManager
private val underTest: PerDisplayInstanceRepositoryImpl<TestPerDisplayInstance> =
- kosmos.fakePerDisplayInstanceRepository
+ kosmos.createPerDisplayInstanceRepository(overrideLifecycleManager = null)
@Before
fun addDisplays() = runBlocking {
@@ -109,6 +110,43 @@ class PerDisplayInstanceRepositoryImplTest : SysuiTestCase() {
verify(kosmos.dumpManager).registerNormalDumpable(anyString(), any())
}
+ @Test
+ fun perDisplay_afterCustomLifecycleManagerRemovesDisplay_destroyInstanceInvoked() =
+ testScope.runTest {
+ val underTest =
+ kosmos.createPerDisplayInstanceRepository(
+ overrideLifecycleManager = lifecycleManager
+ )
+ // Let's start with both
+ lifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY_ID, NON_DEFAULT_DISPLAY_ID)
+
+ val instance = underTest[NON_DEFAULT_DISPLAY_ID]
+
+ lifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY_ID)
+
+ // Now that the lifecycle manager says so, let's make sure it was destroyed
+ assertThat(fakePerDisplayInstanceProviderWithTeardown.destroyed)
+ .containsExactly(instance)
+ }
+
+ @Test
+ fun perDisplay_lifecycleManagerDoesNotContainIt_displayRepositoryDoes_returnsNull() =
+ testScope.runTest {
+ val underTest =
+ kosmos.createPerDisplayInstanceRepository(
+ overrideLifecycleManager = lifecycleManager
+ )
+ // only default display, so getting for the non-default one should fail, despite the
+ // repository having both displays already
+ lifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY_ID)
+
+ assertThat(underTest[NON_DEFAULT_DISPLAY_ID]).isNull()
+
+ lifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY_ID, NON_DEFAULT_DISPLAY_ID)
+
+ assertThat(underTest[NON_DEFAULT_DISPLAY_ID]).isNotNull()
+ }
+
private fun createDisplay(displayId: Int): Display =
display(type = Display.TYPE_INTERNAL, id = displayId)
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 14b13d105482..24b955152093 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -286,7 +286,9 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mLaunchSourceId);
final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS)
.putExtra(Intent.EXTRA_COMPONENT_NAME,
- ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
+ ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString())
+ .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
+
mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
mDialogTransitionAnimator.createActivityTransitionController(
dialog));
@@ -588,9 +590,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
com.android.internal.R.color.materialColorOnPrimaryContainer));
}
text.setText(item.getToolName());
- Intent intent = item.getToolIntent()
- .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
-
+ Intent intent = item.getToolIntent();
view.setOnClickListener(v -> {
final String name = intent.getComponent() != null
? intent.getComponent().flattenToString()
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 908d0aafb2b9..02d9c664fcc5 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -33,6 +33,8 @@ import com.android.systemui.display.data.repository.DisplayScopeRepository
import com.android.systemui.display.data.repository.DisplayScopeRepositoryImpl
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepositoryImpl
+import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepository
+import com.android.systemui.display.data.repository.DisplaysWithDecorationsRepositoryImpl
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
import com.android.systemui.display.data.repository.PerDisplayRepoDumpHelper
@@ -84,6 +86,11 @@ interface DisplayModule {
): DisplayWindowPropertiesRepository
@Binds
+ fun displaysWithDecorationsRepository(
+ impl: DisplaysWithDecorationsRepositoryImpl
+ ): DisplaysWithDecorationsRepository
+
+ @Binds
fun dumpRegistrationLambda(helper: PerDisplayRepoDumpHelper): PerDisplayRepository.InitCallback
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 051fe7e5517c..01bbf2d57dd6 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -16,95 +16,25 @@
package com.android.systemui.display.data.repository
-import android.annotation.SuppressLint
-import android.view.IWindowManager
import com.android.app.displaylib.DisplayRepository as DisplayRepositoryFromLib
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.statusbar.CommandQueue
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.scan
-import kotlinx.coroutines.flow.stateIn
-/** Repository for providing access to display related information and events. */
-interface DisplayRepository : DisplayRepositoryFromLib {
-
- /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
- val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
-}
+/**
+ * Repository for providing access to display related information and events.
+ *
+ * This is now just an interface that extends [DisplayRepositoryFromLib] to avoid changing all the
+ * imports in sysui using this interface.
+ */
+interface DisplayRepository : DisplayRepositoryFromLib, DisplaysWithDecorationsRepository
@SysUISingleton
-@SuppressLint("SharedFlowCreation")
class DisplayRepositoryImpl
@Inject
constructor(
- private val commandQueue: CommandQueue,
- private val windowManager: IWindowManager,
- @Background bgApplicationScope: CoroutineScope,
private val displayRepositoryFromLib: com.android.app.displaylib.DisplayRepository,
-) : DisplayRepositoryFromLib by displayRepositoryFromLib, DisplayRepository {
-
- private val decorationEvents: Flow<Event> = callbackFlow {
- val callback =
- object : CommandQueue.Callbacks {
- override fun onDisplayAddSystemDecorations(displayId: Int) {
- trySend(Event.Add(displayId))
- }
-
- override fun onDisplayRemoveSystemDecorations(displayId: Int) {
- trySend(Event.Remove(displayId))
- }
- }
- commandQueue.addCallback(callback)
- awaitClose { commandQueue.removeCallback(callback) }
- }
-
- private val initialDisplayIdsWithDecorations: Set<Int> =
- displayIds.value.filter { windowManager.shouldShowSystemDecors(it) }.toSet()
-
- /**
- * A [StateFlow] that maintains a set of display IDs that should have system decorations.
- *
- * Updates to the set are triggered by:
- * - Adding displays via [CommandQueue.Callbacks.onDisplayAddSystemDecorations].
- * - Removing displays via [CommandQueue.Callbacks.onDisplayRemoveSystemDecorations].
- * - Removing displays via [displayRemovalEvent] emissions.
- *
- * The set is initialized with displays that qualify for system decorations based on
- * [WindowManager.shouldShowSystemDecors].
- */
- override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
- merge(decorationEvents, displayRemovalEvent.map { Event.Remove(it) })
- .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event ->
- when (event) {
- is Event.Add -> displayIds + event.displayId
- is Event.Remove -> displayIds - event.displayId
- }
- }
- .distinctUntilChanged()
- .stateIn(
- scope = bgApplicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = initialDisplayIdsWithDecorations,
- )
-
- private sealed class Event(val displayId: Int) {
- class Add(displayId: Int) : Event(displayId)
-
- class Remove(displayId: Int) : Event(displayId)
- }
-
- private companion object {
- const val TAG = "DisplayRepository"
- }
-}
+ private val displaysWithDecorationsRepositoryImpl: DisplaysWithDecorationsRepository,
+) :
+ DisplayRepositoryFromLib by displayRepositoryFromLib,
+ DisplaysWithDecorationsRepository by displaysWithDecorationsRepositoryImpl,
+ DisplayRepository
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt
new file mode 100644
index 000000000000..f4a2ed48f295
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplaysWithDecorationsRepository.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.view.IWindowManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.CommandQueue
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.scan
+import kotlinx.coroutines.flow.stateIn
+
+/** Provides the displays with decorations. */
+interface DisplaysWithDecorationsRepository {
+ /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
+ val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
+}
+
+@SysUISingleton
+class DisplaysWithDecorationsRepositoryImpl
+@Inject
+constructor(
+ private val commandQueue: CommandQueue,
+ private val windowManager: IWindowManager,
+ @Background bgApplicationScope: CoroutineScope,
+ displayRepository: com.android.app.displaylib.DisplayRepository,
+) : DisplaysWithDecorationsRepository {
+
+ private val decorationEvents: Flow<Event> = callbackFlow {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun onDisplayAddSystemDecorations(displayId: Int) {
+ trySend(Event.Add(displayId))
+ }
+
+ override fun onDisplayRemoveSystemDecorations(displayId: Int) {
+ trySend(Event.Remove(displayId))
+ }
+ }
+ commandQueue.addCallback(callback)
+ awaitClose { commandQueue.removeCallback(callback) }
+ }
+
+ private val initialDisplayIdsWithDecorations: Set<Int> =
+ displayRepository.displayIds.value
+ .filter { windowManager.shouldShowSystemDecors(it) }
+ .toSet()
+
+ /**
+ * A [StateFlow] that maintains a set of display IDs that should have system decorations.
+ *
+ * Updates to the set are triggered by:
+ * - Adding displays via [CommandQueue.Callbacks.onDisplayAddSystemDecorations].
+ * - Removing displays via [CommandQueue.Callbacks.onDisplayRemoveSystemDecorations].
+ * - Removing displays via [displayRemovalEvent] emissions.
+ *
+ * The set is initialized with displays that qualify for system decorations based on
+ * [WindowManager.shouldShowSystemDecors].
+ */
+ override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
+ merge(decorationEvents, displayRepository.displayRemovalEvent.map { Event.Remove(it) })
+ .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event ->
+ when (event) {
+ is Event.Add -> displayIds + event.displayId
+ is Event.Remove -> displayIds - event.displayId
+ }
+ }
+ .distinctUntilChanged()
+ .stateIn(
+ scope = bgApplicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = initialDisplayIdsWithDecorations,
+ )
+
+ private sealed class Event(val displayId: Int) {
+ class Add(displayId: Int) : Event(displayId)
+
+ class Remove(displayId: Int) : Event(displayId)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 237ec7cfce7f..6cda192c4198 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -22,6 +22,7 @@ import static android.view.MotionEvent.TOOL_TYPE_FINGER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static com.android.systemui.Flags.edgebackGestureHandlerGetRunningTasksBackground;
+import static com.android.systemui.Flags.predictiveBackDelayWmTransition;
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED;
@@ -1182,6 +1183,9 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
return;
} else if (dx > dy && dx > mTouchSlop) {
if (mAllowGesture) {
+ if (!predictiveBackDelayWmTransition() && mBackAnimation != null) {
+ mBackAnimation.onThresholdCrossed();
+ }
if (mBackAnimation == null) {
pilferPointers();
}
@@ -1197,7 +1201,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
// forward touch
mEdgeBackPlugin.onMotionEvent(ev);
dispatchToBackAnimation(ev);
- if (mBackAnimation != null && mThresholdCrossed && !mLastFrameThresholdCrossed) {
+ if (predictiveBackDelayWmTransition() && mBackAnimation != null
+ && mThresholdCrossed && !mLastFrameThresholdCrossed) {
mBackAnimation.onThresholdCrossed();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 922afc7825c4..9cae6c135fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -329,6 +329,7 @@ constructor(
cookie,
component,
launchCujType = Cuj.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
+ returnCujType = Cuj.CUJ_STATUS_BAR_APP_RETURN_TO_CALL_CHIP,
) {
override suspend fun createController(
forLaunch: Boolean
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
index 4b516e9c74bc..161e06295852 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
@@ -16,6 +16,8 @@
package com.android.systemui.display.data.repository
+import com.android.app.displaylib.DisplayInstanceLifecycleManager
+import com.android.app.displaylib.FakeDisplayInstanceLifecycleManager
import com.android.app.displaylib.PerDisplayInstanceProviderWithTeardown
import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl
import com.android.systemui.dump.dumpManager
@@ -69,13 +71,25 @@ val Kosmos.fakePerDisplayInstanceProviderWithTeardown by
Kosmos.Fixture { FakePerDisplayInstanceProviderWithTeardown() }
val Kosmos.perDisplayDumpHelper by Kosmos.Fixture { PerDisplayRepoDumpHelper(dumpManager) }
+val Kosmos.fakeDisplayInstanceLifecycleManager by
+ Kosmos.Fixture { FakeDisplayInstanceLifecycleManager() }
+
val Kosmos.fakePerDisplayInstanceRepository by
Kosmos.Fixture {
- PerDisplayInstanceRepositoryImpl(
- debugName = "fakePerDisplayInstanceRepository",
- instanceProvider = fakePerDisplayInstanceProviderWithTeardown,
- testScope.backgroundScope,
- displayRepository,
- perDisplayDumpHelper,
- )
+ { lifecycleManager: DisplayInstanceLifecycleManager? ->
+ PerDisplayInstanceRepositoryImpl(
+ debugName = "fakePerDisplayInstanceRepository",
+ instanceProvider = fakePerDisplayInstanceProviderWithTeardown,
+ lifecycleManager,
+ testScope.backgroundScope,
+ displayRepository,
+ perDisplayDumpHelper,
+ )
+ }
}
+
+fun Kosmos.createPerDisplayInstanceRepository(
+ overrideLifecycleManager: DisplayInstanceLifecycleManager? = null
+): PerDisplayInstanceRepositoryImpl<TestPerDisplayInstance> {
+ return fakePerDisplayInstanceRepository(overrideLifecycleManager)
+}
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index f5fb644502ab..2fc9a88a9318 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -366,11 +366,46 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_systemAndLock() throws IOException {
- mWallpaperBackupAgent.mIsDeviceInRestore = true;
+ public void testUpdateWallpaperComponent_immediate_systemAndLock() throws IOException {
+ mWallpaperBackupAgent.mPackageExists = true;
+
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
/* which */ FLAG_LOCK | FLAG_SYSTEM);
+ assertThat(mWallpaperBackupAgent.mGetPackageMonitorCallCount).isEqualTo(0);
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never()).clear(anyInt());
+ }
+
+ @Test
+ public void testUpdateWallpaperComponent_immediate_systemOnly()
+ throws IOException {
+ mWallpaperBackupAgent.mPackageExists = true;
+
+ mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
+ /* which */ FLAG_SYSTEM);
+
+ assertThat(mWallpaperBackupAgent.mGetPackageMonitorCallCount).isEqualTo(0);
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never()).clear(anyInt());
+ }
+
+ @Test
+ public void testUpdateWallpaperComponent_delayed_systemAndLock() throws IOException {
+ mWallpaperBackupAgent.mIsDeviceInRestore = true;
+
+ mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -384,13 +419,12 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_systemOnly()
+ public void testUpdateWallpaperComponent_delayed_systemOnly()
throws IOException {
mWallpaperBackupAgent.mIsDeviceInRestore = true;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
/* which */ FLAG_SYSTEM);
-
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -405,7 +439,7 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_deviceNotInRestore_doesNotApply()
+ public void testUpdateWallpaperComponent_delayed_deviceNotInRestore_doesNotApply()
throws IOException {
mWallpaperBackupAgent.mIsDeviceInRestore = false;
@@ -421,7 +455,7 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_differentPackageInstalled_doesNotApply()
+ public void testUpdateWallpaperComponent_delayed_differentPackageInstalled_doesNotApply()
throws IOException {
mWallpaperBackupAgent.mIsDeviceInRestore = false;
@@ -745,9 +779,8 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_delayedRestore_logsSuccess() throws Exception {
+ public void testUpdateWallpaperComponent_delayed_succeeds_logsSuccess() throws Exception {
mWallpaperBackupAgent.mIsDeviceInRestore = true;
- when(mWallpaperManager.setWallpaperComponent(any())).thenReturn(true);
when(mWallpaperManager.setWallpaperComponentWithFlags(any(), eq(FLAG_LOCK | FLAG_SYSTEM)))
.thenReturn(true);
BackupRestoreEventLogger logger = new BackupRestoreEventLogger(
@@ -771,9 +804,8 @@ public class WallpaperBackupAgentTest {
@Test
- public void testUpdateWallpaperComponent_delayedRestoreFails_logsFailure() throws Exception {
+ public void testUpdateWallpaperComponent_delayed_fails_logsFailure() throws Exception {
mWallpaperBackupAgent.mIsDeviceInRestore = true;
- when(mWallpaperManager.setWallpaperComponent(any())).thenReturn(false);
BackupRestoreEventLogger logger = new BackupRestoreEventLogger(
BackupAnnotations.OperationType.RESTORE);
when(mBackupManager.getDelayedRestoreLogger()).thenReturn(logger);
@@ -793,7 +825,7 @@ public class WallpaperBackupAgentTest {
}
@Test
- public void testUpdateWallpaperComponent_delayedRestore_packageNotInstalled_logsFailure()
+ public void testUpdateWallpaperComponent_delayed_packageNotInstalled_logsFailure()
throws Exception {
mWallpaperBackupAgent.mIsDeviceInRestore = false;
BackupRestoreEventLogger logger = new BackupRestoreEventLogger(
@@ -990,6 +1022,8 @@ public class WallpaperBackupAgentTest {
List<File> mBackedUpFiles = new ArrayList<>();
PackageMonitor mWallpaperPackageMonitor;
boolean mIsDeviceInRestore = false;
+ boolean mPackageExists = false;
+ int mGetPackageMonitorCallCount = 0;
@Override
protected void backupFile(File file, FullBackupDataOutput data) {
@@ -998,7 +1032,7 @@ public class WallpaperBackupAgentTest {
@Override
boolean servicePackageExists(ComponentName comp) {
- return false;
+ return mPackageExists;
}
@Override
@@ -1008,6 +1042,7 @@ public class WallpaperBackupAgentTest {
@Override
PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, int which) {
+ mGetPackageMonitorCallCount++;
mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(componentName, which);
return mWallpaperPackageMonitor;
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 517279bd7527..8b3eb48fc783 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -98,6 +98,9 @@ public final class AppStartInfoTracker {
@VisibleForTesting static final int APP_START_INFO_HISTORY_LIST_SIZE = 16;
+ @VisibleForTesting
+ static final long APP_START_INFO_HISTORY_LENGTH_MS = TimeUnit.DAYS.toMillis(14);
+
/**
* The max number of records that can be present in {@link mInProgressRecords}.
*
@@ -120,9 +123,13 @@ public final class AppStartInfoTracker {
* Monotonic clock which does not reset on reboot.
*
* Time for offset is persisted along with records, see {@link #persistProcessStartInfo}.
- * This does not follow the recommendation of {@link MonotonicClock} to persist on shutdown as
- * it's ok in this case to lose any time change past the last persist as records added since
- * then will be lost as well and the purpose of this clock is to keep records in order.
+ * This does not currently follow the recommendation of {@link MonotonicClock} to persist on
+ * shutdown as it's ok in this case to lose any time change past the last persist as records
+ * added since then will be lost as well. Since this time is used for cleanup as well, the
+ * potential old offset may result in the cleanup window being extended slightly beyond the
+ * targeted 14 days.
+ *
+ * TODO: b/402794215 - Persist on shutdown once persist performance is sufficiently improved.
*/
@VisibleForTesting MonotonicClock mMonotonicClock = null;
@@ -296,7 +303,7 @@ public final class AppStartInfoTracker {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTime());
+ ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTimeMs());
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
start.setIntent(intent);
start.setStartType(ApplicationStartInfo.START_TYPE_UNSET);
@@ -454,7 +461,7 @@ public final class AppStartInfoTracker {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTime());
+ ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTimeMs());
addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
start.addStartupTimestamp(
@@ -484,7 +491,7 @@ public final class AppStartInfoTracker {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTime());
+ ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTimeMs());
addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
start.addStartupTimestamp(
@@ -511,7 +518,7 @@ public final class AppStartInfoTracker {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTime());
+ ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTimeMs());
addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
start.addStartupTimestamp(
@@ -533,7 +540,7 @@ public final class AppStartInfoTracker {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTime());
+ ApplicationStartInfo start = new ApplicationStartInfo(getMonotonicTimeMs());
addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
start.addStartupTimestamp(
@@ -721,8 +728,8 @@ public final class AppStartInfoTracker {
Collections.sort(
list, (a, b) ->
- Long.compare(b.getMonoticCreationTimeMs(),
- a.getMonoticCreationTimeMs()));
+ Long.compare(b.getMonotonicCreationTimeMs(),
+ a.getMonotonicCreationTimeMs()));
int size = list.size();
if (maxNum > 0) {
size = Math.min(size, maxNum);
@@ -1098,7 +1105,7 @@ public final class AppStartInfoTracker {
mLastAppStartInfoPersistTimestamp = now;
}
}
- proto.write(AppsStartInfoProto.MONOTONIC_TIME, getMonotonicTime());
+ proto.write(AppsStartInfoProto.MONOTONIC_TIME, getMonotonicTimeMs());
if (succeeded) {
proto.flush();
af.finishWrite(out);
@@ -1219,7 +1226,11 @@ public final class AppStartInfoTracker {
}
}
- private long getMonotonicTime() {
+ /**
+ * Monotonic time that doesn't change with reboot or device time change for ordering records.
+ */
+ @VisibleForTesting
+ public long getMonotonicTimeMs() {
if (mMonotonicClock == null) {
// This should never happen. Return 0 to not interfere with past or future records.
return 0;
@@ -1229,7 +1240,7 @@ public final class AppStartInfoTracker {
/** A container class of (@link android.app.ApplicationStartInfo) */
final class AppStartInfoContainer {
- private ArrayList<ApplicationStartInfo> mInfos; // Always kept sorted by first timestamp.
+ private ArrayList<ApplicationStartInfo> mInfos; // Always kept sorted by monotonic time.
private int mMaxCapacity;
private int mUid;
private boolean mMonitoringModeEnabled = false;
@@ -1260,9 +1271,12 @@ public final class AppStartInfoTracker {
return;
}
- // Sort records so we can remove the least recent ones.
- Collections.sort(mInfos, (a, b) ->
- Long.compare(b.getMonoticCreationTimeMs(), a.getMonoticCreationTimeMs()));
+ if (!android.app.Flags.appStartInfoKeepRecordsSorted()) {
+ // Sort records so we can remove the least recent ones.
+ Collections.sort(mInfos, (a, b) ->
+ Long.compare(b.getMonotonicCreationTimeMs(),
+ a.getMonotonicCreationTimeMs()));
+ }
// Remove records and trim list object back to size.
mInfos.subList(0, mInfos.size() - getMaxCapacity()).clear();
@@ -1277,25 +1291,34 @@ public final class AppStartInfoTracker {
@GuardedBy("mLock")
void addStartInfoLocked(ApplicationStartInfo info) {
- int size = mInfos.size();
- if (size >= getMaxCapacity()) {
- // Remove oldest record if size is over max capacity.
- int oldestIndex = -1;
- long oldestTimeStamp = Long.MAX_VALUE;
- for (int i = 0; i < size; i++) {
- ApplicationStartInfo startInfo = mInfos.get(i);
- if (startInfo.getMonoticCreationTimeMs() < oldestTimeStamp) {
- oldestTimeStamp = startInfo.getMonoticCreationTimeMs();
- oldestIndex = i;
- }
+ if (android.app.Flags.appStartInfoKeepRecordsSorted()) {
+ while (mInfos.size() >= getMaxCapacity()) {
+ // Expected to execute at most once.
+ mInfos.removeLast();
}
- if (oldestIndex >= 0) {
- mInfos.remove(oldestIndex);
+ mInfos.addFirst(info);
+ } else {
+ int size = mInfos.size();
+ if (size >= getMaxCapacity()) {
+ // Remove oldest record if size is over max capacity.
+ int oldestIndex = -1;
+ long oldestTimeStamp = Long.MAX_VALUE;
+ for (int i = 0; i < size; i++) {
+ ApplicationStartInfo startInfo = mInfos.get(i);
+ if (startInfo.getMonotonicCreationTimeMs() < oldestTimeStamp) {
+ oldestTimeStamp = startInfo.getMonotonicCreationTimeMs();
+ oldestIndex = i;
+ }
+ }
+ if (oldestIndex >= 0) {
+ mInfos.remove(oldestIndex);
+ }
}
+ mInfos.add(info);
+ Collections.sort(mInfos, (a, b) ->
+ Long.compare(b.getMonotonicCreationTimeMs(),
+ a.getMonotonicCreationTimeMs()));
}
- mInfos.add(info);
- Collections.sort(mInfos, (a, b) ->
- Long.compare(b.getMonoticCreationTimeMs(), a.getMonoticCreationTimeMs()));
}
/**
@@ -1439,9 +1462,25 @@ public final class AppStartInfoTracker {
long token = proto.start(fieldId);
proto.write(AppsStartInfoProto.Package.User.UID, mUid);
int size = mInfos.size();
- for (int i = 0; i < size; i++) {
- mInfos.get(i).writeToProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO,
- byteArrayOutputStream, objectOutputStream, typedXmlSerializer);
+ if (android.app.Flags.appStartInfoCleanupOldRecords()) {
+ long removeOlderThan = getMonotonicTimeMs() - APP_START_INFO_HISTORY_LENGTH_MS;
+ // Iterate backwards so we can remove old records as we go.
+ for (int i = size - 1; i >= 0; i--) {
+ if (mInfos.get(i).getMonotonicCreationTimeMs() < removeOlderThan) {
+ // Remove the record.
+ mInfos.remove(i);
+ } else {
+ mInfos.get(i).writeToProto(
+ proto, AppsStartInfoProto.Package.User.APP_START_INFO,
+ byteArrayOutputStream, objectOutputStream, typedXmlSerializer);
+ }
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ mInfos.get(i).writeToProto(
+ proto, AppsStartInfoProto.Package.User.APP_START_INFO,
+ byteArrayOutputStream, objectOutputStream, typedXmlSerializer);
+ }
}
proto.write(AppsStartInfoProto.Package.User.MONITORING_ENABLED, mMonitoringModeEnabled);
proto.end(token);
@@ -1466,7 +1505,13 @@ public final class AppStartInfoTracker {
info.readFromProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO,
byteArrayInputStream, objectInputStream, typedXmlPullParser);
info.setPackageName(packageName);
- mInfos.add(info);
+ if (android.app.Flags.appStartInfoKeepRecordsSorted()) {
+ // Since the writes are done from oldest to newest, each additional
+ // record will be newer than the previous so use addFirst.
+ mInfos.addFirst(info);
+ } else {
+ mInfos.add(info);
+ }
break;
case (int) AppsStartInfoProto.Package.User.MONITORING_ENABLED:
mMonitoringModeEnabled = proto.readBoolean(
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6e6d00d62819..d9db178e0dc2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1230,7 +1230,7 @@ public class InputManagerService extends IInputManager.Stub
"registerTabletModeChangedListener()")) {
throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
}
- Objects.requireNonNull(listener, "listener must not be null");
+ Objects.requireNonNull(listener, "event must not be null");
synchronized (mTabletModeLock) {
final int callingPid = Binder.getCallingPid();
@@ -1342,7 +1342,7 @@ public class InputManagerService extends IInputManager.Stub
@Override
public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) {
- Objects.requireNonNull(inputChannelToken, "inputChannelToken must not be null");
+ Objects.requireNonNull(inputChannelToken, "event must not be null");
mNative.requestPointerCapture(inputChannelToken, enabled);
}
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index f5daa8036726..8c3b7c606f04 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -17,11 +17,13 @@
package com.android.server.security.advancedprotection;
import static android.provider.Settings.Secure.ADVANCED_PROTECTION_MODE;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.Manifest;
import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.StatsManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Binder;
@@ -45,6 +47,7 @@ import android.security.advancedprotection.IAdvancedProtectionService;
import android.security.advancedprotection.AdvancedProtectionProtoEnums;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.StatsEvent;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
@@ -137,6 +140,15 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
mProviders.add(new DisallowWepAdvancedProtectionProvider());
}
+ private void initLogging() {
+ StatsManager statsManager = mContext.getSystemService(StatsManager.class);
+ statsManager.setPullAtomCallback(
+ FrameworkStatsLog.ADVANCED_PROTECTION_STATE_INFO,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ new AdvancedProtectionStatePullAtomCallback());
+ }
+
// Only for tests
@VisibleForTesting
AdvancedProtectionService(@NonNull Context context, @NonNull AdvancedProtectionStore store,
@@ -399,6 +411,7 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
Slog.i(TAG, "Advanced protection is enabled");
}
mService.initFeatures(enabled);
+ mService.initLogging();
}
}
}
@@ -500,4 +513,22 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
}
}
+
+ private class AdvancedProtectionStatePullAtomCallback
+ implements StatsManager.StatsPullAtomCallback {
+
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> data) {
+ if (atomTag != FrameworkStatsLog.ADVANCED_PROTECTION_STATE_INFO) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ data.add(
+ FrameworkStatsLog.buildStatsEvent(
+ FrameworkStatsLog.ADVANCED_PROTECTION_STATE_INFO,
+ /*enabled*/ isAdvancedProtectionEnabledInternal(),
+ /*hours_since_enabled*/ hoursSinceLastChange()));
+ return StatsManager.PULL_SUCCESS;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index a731bf7c64b3..70fc6bace868 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -82,6 +82,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer,
*/
@VisibleForTesting
static final int SNAPSHOT_MODE_NONE = 2;
+ static final float THEME_SNAPSHOT_MIN_Length = 128.0f;
protected final WindowManagerService mService;
protected final float mHighResSnapshotScale;
@@ -436,14 +437,21 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer,
final Rect taskBounds = source.getBounds();
final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride();
final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
+ final int taskWidth = taskBounds.width();
+ final int taskHeight = taskBounds.height();
+ float scale = mHighResSnapshotScale;
+ if (Flags.reduceTaskSnapshotMemoryUsage()) {
+ final int minLength = Math.min(taskWidth, taskHeight);
+ if (THEME_SNAPSHOT_MIN_Length < minLength) {
+ scale = Math.min(THEME_SNAPSHOT_MIN_Length / minLength, scale);
+ }
+ }
final SnapshotDrawerUtils.SystemBarBackgroundPainter
decorPainter = new SnapshotDrawerUtils.SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.insetsFlags.appearance, taskDescription,
- mHighResSnapshotScale, mainWindow.getRequestedVisibleTypes());
- final int taskWidth = taskBounds.width();
- final int taskHeight = taskBounds.height();
- final int width = (int) (taskWidth * mHighResSnapshotScale);
- final int height = (int) (taskHeight * mHighResSnapshotScale);
+ scale, mainWindow.getRequestedVisibleTypes());
+ final int width = (int) (taskWidth * scale);
+ final int height = (int) (taskHeight * scale);
final RenderNode node = RenderNode.create("SnapshotController", null);
node.setLeftTopRightBottom(0, 0, width, height);
node.setClipToBounds(false);
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index fee5566af484..d8087265c1d3 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -69,11 +69,11 @@ public class DesktopAppCompatAspectRatioPolicy {
* Calculates the final aspect ratio of an launching activity based on the task it will be
* launched in. Takes into account any min or max aspect ratio constraints.
*/
- float calculateAspectRatio(@NonNull Task task) {
+ float calculateAspectRatio(@NonNull Task task, boolean hasOrientationMismatch) {
final float maxAspectRatio = getMaxAspectRatio();
final float minAspectRatio = getMinAspectRatio(task);
float desiredAspectRatio = 0;
- desiredAspectRatio = getDesiredAspectRatio(task);
+ desiredAspectRatio = getDesiredAspectRatio(task, hasOrientationMismatch);
if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
desiredAspectRatio = maxAspectRatio;
} else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
@@ -87,13 +87,14 @@ public class DesktopAppCompatAspectRatioPolicy {
* any min or max aspect ratio constraints.
*/
@VisibleForTesting
- float getDesiredAspectRatio(@NonNull Task task) {
+ float getDesiredAspectRatio(@NonNull Task task, boolean hasOrientationMismatch) {
final float letterboxAspectRatioOverride = getFixedOrientationLetterboxAspectRatio(task);
// Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
// be respected in #calculateAspectRatio.
if (isDefaultMultiWindowLetterboxAspectRatioDesired(task)) {
return DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
- } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
+ } else if (hasOrientationMismatch
+ && letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
return letterboxAspectRatioOverride;
}
return AppCompatUtils.computeAspectRatio(task.getDisplayArea().getBounds());
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index d9354323ae7c..83ca5f6f83f4 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.isFixedOrientation;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
@@ -32,8 +31,8 @@ import static com.android.server.wm.LaunchParamsUtil.calculateLayoutBounds;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.pm.ActivityInfo.WindowLayout;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.Size;
@@ -152,19 +151,25 @@ public final class DesktopModeBoundsCalculator {
}
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
activity.mAppCompatController.getDesktopAspectRatioPolicy();
- float appAspectRatio = desktopAppCompatAspectRatioPolicy.calculateAspectRatio(task);
+ final int stableBoundsOrientation = stableBounds.height() >= stableBounds.width()
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ int activityOrientation = getActivityConfigurationOrientation(
+ activity, task, stableBoundsOrientation);
+ // Use orientation mismatch to resolve aspect ratio to match fixed orientation letterboxing
+ // policy in {@link ActivityRecord.resolveFixedOrientationConfiguration}
+ final boolean hasOrientationMismatch = stableBoundsOrientation != activityOrientation;
+ float appAspectRatio = desktopAppCompatAspectRatioPolicy.calculateAspectRatio(
+ task, hasOrientationMismatch);
final float tdaWidth = stableBounds.width();
final float tdaHeight = stableBounds.height();
- final int taskConfigOrientation = task.getConfiguration().orientation;
- final int activityOrientation = getActivityOrientation(activity, task);
- final Size initialSize = switch (taskConfigOrientation) {
+ final Size initialSize = switch (stableBoundsOrientation) {
case ORIENTATION_LANDSCAPE -> {
// Device in landscape orientation.
if (appAspectRatio == 0) {
appAspectRatio = 1;
}
if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, task)) {
- if (isFixedOrientationPortrait(activityOrientation)) {
+ if (hasOrientationMismatch) {
// For portrait resizeable activities, respect apps fullscreen width but
// apply ideal size height.
yield new Size((int) ((tdaHeight / appAspectRatio) + 0.5f),
@@ -183,7 +188,7 @@ public final class DesktopModeBoundsCalculator {
final int customPortraitWidthForLandscapeApp = screenBounds.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
if (canChangeAspectRatio(desktopAppCompatAspectRatioPolicy, task)) {
- if (isFixedOrientationLandscape(activityOrientation)) {
+ if (hasOrientationMismatch) {
if (appAspectRatio == 0) {
appAspectRatio = tdaWidth / (tdaWidth - 1);
}
@@ -198,7 +203,7 @@ public final class DesktopModeBoundsCalculator {
if (appAspectRatio == 0) {
appAspectRatio = 1;
}
- if (isFixedOrientationLandscape(activityOrientation)) {
+ if (hasOrientationMismatch) {
// For landscape unresizeable activities, apply custom app width to ideal size
// and calculate maximum size with this area while maintaining original aspect
// ratio.
@@ -230,19 +235,23 @@ public final class DesktopModeBoundsCalculator {
&& !desktopAppCompatAspectRatioPolicy.hasMinAspectRatioOverride(task);
}
- private static @ScreenOrientation int getActivityOrientation(
- @NonNull ActivityRecord activity, @NonNull Task task) {
+ private static @Configuration.Orientation int getActivityConfigurationOrientation(
+ @NonNull ActivityRecord activity, @NonNull Task task,
+ @Configuration.Orientation int stableBoundsOrientation) {
final int activityOrientation = activity.getOverrideOrientation();
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
activity.mAppCompatController.getDesktopAspectRatioPolicy();
- if (desktopAppCompatAspectRatioPolicy.shouldApplyUserMinAspectRatioOverride(task)
+ if ((desktopAppCompatAspectRatioPolicy.shouldApplyUserMinAspectRatioOverride(task)
&& (!isFixedOrientation(activityOrientation)
- || activityOrientation == SCREEN_ORIENTATION_LOCKED)) {
+ || activityOrientation == SCREEN_ORIENTATION_LOCKED))
+ || isFixedOrientationPortrait(activityOrientation)) {
// If a user aspect ratio override should be applied, treat the activity as portrait if
// it has not specified a fix orientation.
- return SCREEN_ORIENTATION_PORTRAIT;
+ return ORIENTATION_PORTRAIT;
}
- return activityOrientation;
+ // If activity orientation is undefined inherit task orientation.
+ return isFixedOrientationLandscape(activityOrientation)
+ ? ORIENTATION_LANDSCAPE : stableBoundsOrientation;
}
/**
@@ -252,7 +261,7 @@ public final class DesktopModeBoundsCalculator {
// TODO(b/400617906): Merge duplicate initial bounds calculations to shared class.
@NonNull
private static Size maximizeSizeGivenAspectRatio(
- @ScreenOrientation int orientation,
+ @Configuration.Orientation int orientation,
@NonNull Size targetArea,
float aspectRatio,
int captionHeight
@@ -261,7 +270,7 @@ public final class DesktopModeBoundsCalculator {
final int targetWidth = targetArea.getWidth();
final int finalHeight;
final int finalWidth;
- if (isFixedOrientationPortrait(orientation)) {
+ if (orientation == ORIENTATION_PORTRAIT) {
// Portrait activity.
// Calculate required width given ideal height and aspect ratio.
int tempWidth = (int) (targetHeight / aspectRatio);
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index eafc8be7bf77..016cebac2b86 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -24,6 +24,10 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
@@ -33,10 +37,12 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.TransitionAnimation;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
+import com.android.window.flags.Flags;
import java.io.File;
import java.io.FileOutputStream;
@@ -400,23 +406,20 @@ class SnapshotPersistQueue {
Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mId);
return false;
}
- final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
- mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
- if (bitmap == null) {
- Slog.e(TAG, "Invalid task snapshot hw bitmap");
- return false;
- }
- final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
+ final HardwareBuffer hwBuffer = mSnapshot.getHardwareBuffer();
+ final int width = hwBuffer.getWidth();
+ final int height = hwBuffer.getHeight();
+ final int pixelFormat = hwBuffer.getFormat();
+ final Bitmap swBitmap = !Flags.reduceTaskSnapshotMemoryUsage()
+ || (pixelFormat != PixelFormat.RGB_565 && pixelFormat != PixelFormat.RGBA_8888)
+ || !mSnapshot.isRealSnapshot()
+ || TransitionAnimation.hasProtectedContent(hwBuffer)
+ ? copyToSwBitmapReadBack()
+ : copyToSwBitmapDirect(width, height, pixelFormat);
if (swBitmap == null) {
- Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig() + ", isMutable="
- + bitmap.isMutable() + ") to (config=ARGB_8888, isMutable=false) failed.");
return false;
}
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
- bitmap.recycle();
-
final File file = mPersistInfoProvider.getHighResolutionBitmapFile(mId, mUserId);
try (FileOutputStream fos = new FileOutputStream(file)) {
swBitmap.compress(JPEG, COMPRESS_QUALITY, fos);
@@ -448,6 +451,58 @@ class SnapshotPersistQueue {
return true;
}
+ private Bitmap copyToSwBitmapReadBack() {
+ final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
+ mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
+ if (bitmap == null) {
+ Slog.e(TAG, "Invalid task snapshot hw bitmap");
+ return null;
+ }
+
+ final Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false /* isMutable */);
+ if (swBitmap == null) {
+ Slog.e(TAG, "Bitmap conversion from (config=" + bitmap.getConfig()
+ + ", isMutable=" + bitmap.isMutable()
+ + ") to (config=ARGB_8888, isMutable=false) failed.");
+ return null;
+ }
+ bitmap.recycle();
+ return swBitmap;
+ }
+
+ /**
+ * Use ImageReader to create the software bitmap, so SkImage won't create an extra texture.
+ */
+ private Bitmap copyToSwBitmapDirect(int width, int height, int pixelFormat) {
+ try (ImageReader ir = ImageReader.newInstance(width, height,
+ pixelFormat, 1 /* maxImages */)) {
+ ir.getSurface().attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
+ mSnapshot.getColorSpace());
+ try (Image image = ir.acquireLatestImage()) {
+ if (image == null || image.getPlaneCount() < 1) {
+ Slog.e(TAG, "Image reader cannot acquire image");
+ return null;
+ }
+
+ final Image.Plane[] planes = image.getPlanes();
+ if (planes.length != 1) {
+ Slog.e(TAG, "Image reader cannot get plane");
+ return null;
+ }
+ final Image.Plane plane = planes[0];
+ final int rowPadding = plane.getRowStride() - plane.getPixelStride()
+ * image.getWidth();
+ final Bitmap swBitmap = Bitmap.createBitmap(
+ image.getWidth() + rowPadding / plane.getPixelStride() /* width */,
+ image.getHeight() /* height */,
+ pixelFormat == PixelFormat.RGB_565
+ ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888);
+ swBitmap.copyPixelsFromBuffer(plane.getBuffer());
+ return swBitmap;
+ }
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8587b5a9c7ca..0531828be6d4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1832,6 +1832,17 @@ class Task extends TaskFragment {
&& supportsMultiWindowInDisplayArea(tda);
}
+ /** Returns true if the task bounds should persist across power cycles. */
+ private static boolean persistTaskBounds(@NonNull WindowConfiguration configuration) {
+ return configuration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+ }
+
+ /** Returns true if the nested task is allowed to have independent bounds from its parent. */
+ private static boolean allowIndependentBoundsFromParent(
+ @NonNull WindowConfiguration configuration) {
+ return configuration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+ }
+
/**
* Check whether this task can be launched on the specified display.
*
@@ -1996,11 +2007,11 @@ class Task extends TaskFragment {
private void onConfigurationChangedInner(Configuration newParentConfig) {
// Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
// restore the last recorded non-fullscreen bounds.
- final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
- boolean nextPersistTaskBounds =
- getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds();
+ final boolean prevPersistTaskBounds = persistTaskBounds(getWindowConfiguration());
+ boolean nextPersistTaskBounds = persistTaskBounds(
+ getRequestedOverrideConfiguration().windowConfiguration);
if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) {
- nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds();
+ nextPersistTaskBounds = persistTaskBounds(newParentConfig.windowConfiguration);
}
// Only restore to the last non-fullscreen bounds when the requested override bounds
// have not been explicitly set already.
@@ -2042,7 +2053,7 @@ class Task extends TaskFragment {
// If the configuration supports persistent bounds (eg. Freeform), keep track of the
// current (non-fullscreen) bounds for persistence.
- if (getWindowConfiguration().persistTaskBounds()) {
+ if (persistTaskBounds(getWindowConfiguration())) {
final Rect currentBounds = getRequestedOverrideBounds();
if (!currentBounds.isEmpty()) {
setLastNonFullscreenBounds(currentBounds);
@@ -2383,33 +2394,48 @@ class Task extends TaskFragment {
}
void updateOverrideConfigurationFromLaunchBounds() {
- // If the task is controlled by another organized task, do not set override
- // configurations and let its parent (organized task) to control it;
final Task rootTask = getRootTask();
- boolean shouldInheritBounds = rootTask != this && rootTask.isOrganized();
- if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
- // Only inherit from organized parent when this task is not organized.
- shouldInheritBounds &= !isOrganized();
+ final boolean hasParentTask = rootTask != this;
+ final int windowingMode = getWindowingMode();
+ final boolean isNonStandardOrFullscreen = !isActivityTypeStandardOrUndefined()
+ || windowingMode == WINDOWING_MODE_FULLSCREEN;
+ if (!Flags.nestedTasksWithIndependentBounds()
+ && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
+ final Rect bounds;
+ if (hasParentTask && rootTask.isOrganized()) {
+ bounds = null;
+ } else if (isNonStandardOrFullscreen) {
+ bounds = isResizeable() ? rootTask.getRequestedOverrideBounds() : null;
+ } else if (!persistTaskBounds(getWindowConfiguration())) {
+ bounds = rootTask.getRequestedOverrideBounds();
+ } else {
+ bounds = mLastNonFullscreenBounds;
+ }
+ setBounds(bounds);
+ return;
}
- final Rect bounds = shouldInheritBounds ? null : getLaunchBounds();
- setBounds(bounds);
- }
- /** Returns the bounds that should be used to launch this task. */
- Rect getLaunchBounds() {
- final Task rootTask = getRootTask();
- if (rootTask == null) {
- return null;
+ // Non-standard/fullscreen unresizable tasks should always inherit.
+ boolean shouldInheritBounds = isNonStandardOrFullscreen && !isResizeable();
+ // Task itself is not organized (e.g. Home), just inherit from its organized parent.
+ shouldInheritBounds |= hasParentTask && rootTask.isOrganized() && !isOrganized();
+ // Nested tasks should inherit when they're not allowed to have independent bounds, such as
+ // in multi-window split-screen.
+ shouldInheritBounds |= hasParentTask
+ && !(allowIndependentBoundsFromParent(getWindowConfiguration())
+ && persistTaskBounds(getWindowConfiguration()));
+ if (shouldInheritBounds) {
+ setBounds(null);
+ return;
}
-
- final int windowingMode = getWindowingMode();
- if (!isActivityTypeStandardOrUndefined()
- || windowingMode == WINDOWING_MODE_FULLSCREEN) {
- return isResizeable() ? rootTask.getRequestedOverrideBounds() : null;
- } else if (!getWindowConfiguration().persistTaskBounds()) {
- return rootTask.getRequestedOverrideBounds();
+ if (!hasParentTask && !persistTaskBounds(getWindowConfiguration())) {
+ // Non-nested, non-persistable tasks such as PIP or multi-window floating windows.
+ return;
}
- return mLastNonFullscreenBounds;
+ // Non-nested, persisted tasks (e.g. top-level freeform) or nested persisted tasks that
+ // allow independent bounds from parent (e.g. nested freeform) should use launch-params
+ // bounds set to |mLastNonFullscreenBounds|.
+ setBounds(mLastNonFullscreenBounds);
}
void setRootProcess(WindowProcessController proc) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
index 987b9c6427d8..3289d70b89ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
@@ -680,6 +680,67 @@ public class ApplicationStartInfoTest {
ApplicationStartInfo.START_TIMESTAMP_FORK));
}
+ /**
+ * Test that cleanup old records works as expected, removing records that are older than the max
+ * retention length.
+ */
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_APP_START_INFO_CLEANUP_OLD_RECORDS)
+ public void testOldRecordsCleanup() throws Exception {
+ // Use a different start timestamp for each record so we can identify which was removed.
+ // This timestamp is not used for ordering and has no impact on removal.
+ final long startTimeRecord1 = 123L;
+ final long startTimeRecord2 = 456L;
+ final long startTimeRecord3 = 789L;
+
+ // Create a process record to use with all starts.
+ ProcessRecord app = makeProcessRecord(
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
+ null, // definingUid
+ APP_1_PROCESS_NAME, // processName
+ APP_1_PACKAGE_NAME); // packageName
+
+ // Set monotonic time to 1, and then trigger a start info record.
+ doReturn(1L).when(mAppStartInfoTracker).getMonotonicTimeMs();
+ mAppStartInfoTracker.handleProcessBroadcastStart(startTimeRecord1, app,
+ buildIntent(COMPONENT), false /* isAlarm */);
+
+ // Set monotonic time to 2, and then trigger another start info record.
+ doReturn(2L).when(mAppStartInfoTracker).getMonotonicTimeMs();
+ mAppStartInfoTracker.handleProcessBroadcastStart(startTimeRecord2, app,
+ buildIntent(COMPONENT), false /* isAlarm */);
+
+ // Set monotonic time to 3, then trigger another start info record.
+ doReturn(3L).when(mAppStartInfoTracker).getMonotonicTimeMs();
+ mAppStartInfoTracker.handleProcessBroadcastStart(startTimeRecord3, app,
+ buildIntent(COMPONENT), false /* isAlarm */);
+
+ // Verify that all 3 records were added successfully.
+ ArrayList<ApplicationStartInfo> list = new ArrayList<ApplicationStartInfo>();
+ mAppStartInfoTracker.getStartInfo(null, APP_1_UID, 0, 0, list);
+ assertEquals(3, list.size());
+ assertEquals(startTimeRecord3, list.get(0).getStartupTimestamps().get(0).longValue());
+ assertEquals(startTimeRecord2, list.get(1).getStartupTimestamps().get(0).longValue());
+ assertEquals(startTimeRecord1, list.get(2).getStartupTimestamps().get(0).longValue());
+
+ // Set monotonic time to max history length + 3 so that the older 2 records will be removed
+ // but that newest 1 will remain.
+ doReturn(AppStartInfoTracker.APP_START_INFO_HISTORY_LENGTH_MS + 3L)
+ .when(mAppStartInfoTracker).getMonotonicTimeMs();
+
+ // Trigger a persist which will trigger the cleanup of old records.
+ mAppStartInfoTracker.persistProcessStartInfo();
+
+ // Now verify that the records older than max were removed, and that the records not older
+ // remain.
+ list.clear();
+ mAppStartInfoTracker.getStartInfo(null, APP_1_UID, 0, 0, list);
+ assertEquals(1, list.size());
+ assertEquals(startTimeRecord3, list.get(0).getStartupTimestamps().get(0).longValue());
+ }
+
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
try {
Field field = clazz.getDeclaredField(fieldName);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
index fa7dcc8ebbc7..81d753b8e079 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
@@ -35,6 +35,7 @@ import static com.android.server.wm.AppCompatConfiguration.DEFAULT_LETTERBOX_ASP
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.pm.ActivityInfo;
@@ -413,7 +414,7 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
void setDesiredAspectRatio(float aspectRatio) {
doReturn(aspectRatio).when(getDesktopAppCompatAspectRatioPolicy())
- .getDesiredAspectRatio(any());
+ .getDesiredAspectRatio(any(), anyBoolean());
}
DesktopAppCompatAspectRatioPolicy getDesktopAppCompatAspectRatioPolicy() {
@@ -422,7 +423,7 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
float calculateAspectRatio() {
return getDesktopAppCompatAspectRatioPolicy().calculateAspectRatio(
- getTopActivity().getTask());
+ getTopActivity().getTask(), /* hasOrientationMismatch */ true);
}
ActivityRecord getTopActivity() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index 00b617e91bfd..f587d6e8c346 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -52,6 +52,7 @@ import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -437,7 +438,7 @@ public class DesktopModeLaunchParamsModifierTests extends
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any(), anyBoolean());
final int desiredWidth =
(int) ((LANDSCAPE_DISPLAY_BOUNDS.height() / LETTERBOX_ASPECT_RATIO) + 0.5f);
@@ -933,7 +934,7 @@ public class DesktopModeLaunchParamsModifierTests extends
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any(), anyBoolean());
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
@@ -1060,7 +1061,7 @@ public class DesktopModeLaunchParamsModifierTests extends
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any(), anyBoolean());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
@@ -1115,7 +1116,7 @@ public class DesktopModeLaunchParamsModifierTests extends
spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any(), anyBoolean());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
@@ -1569,7 +1570,7 @@ public class DesktopModeLaunchParamsModifierTests extends
activity.mAppCompatController.getDesktopAspectRatioPolicy();
spyOn(desktopAppCompatAspectRatioPolicy);
doReturn(aspectRatio).when(desktopAppCompatAspectRatioPolicy)
- .getDesiredAspectRatio(any());
+ .getDesiredAspectRatio(any(), anyBoolean());
}
private void applyUserMinAspectRatioOverride(ActivityRecord activity, int overrideCode,
@@ -1579,7 +1580,7 @@ public class DesktopModeLaunchParamsModifierTests extends
activity.mAppCompatController.getDesktopAspectRatioPolicy();
spyOn(desktopAppCompatAspectRatioPolicy);
doReturn(1f).when(desktopAppCompatAspectRatioPolicy)
- .getDesiredAspectRatio(any());
+ .getDesiredAspectRatio(any(), anyBoolean());
// Enable user aspect ratio settings
final AppCompatConfiguration appCompatConfiguration =