diff options
14 files changed, 236 insertions, 61 deletions
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 9099f9855eab..7eb6f2e2b331 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -284,7 +284,7 @@ public final class PointerIcon implements Parcelable { if (bitmap == null) { throw new IllegalArgumentException("bitmap must not be null"); } - validateHotSpot(bitmap, hotSpotX, hotSpotY); + validateHotSpot(bitmap, hotSpotX, hotSpotY, false /* isScaled */); PointerIcon icon = new PointerIcon(TYPE_CUSTOM); icon.mBitmap = bitmap; @@ -517,7 +517,9 @@ public final class PointerIcon implements Parcelable { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable); - validateHotSpot(bitmap, hotSpotX, hotSpotY); + // The bitmap and hotspot are loaded from the context, which means it is implicitly scaled + // to the current display density, so treat this as a scaled icon when verifying hotspot. + validateHotSpot(bitmap, hotSpotX, hotSpotY, true /* isScaled */); // Set the properties now that we have successfully loaded the icon. mBitmap = bitmap; mHotSpotX = hotSpotX; @@ -531,11 +533,16 @@ public final class PointerIcon implements Parcelable { + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}"; } - private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) { - if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) { + private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY, + boolean isScaled) { + // Be more lenient when checking the hotspot for scaled icons to account for the restriction + // that bitmaps must have an integer size. + if (hotSpotX < 0 || (isScaled ? (int) hotSpotX > bitmap.getWidth() + : hotSpotX >= bitmap.getWidth())) { throw new IllegalArgumentException("x hotspot lies outside of the bitmap area"); } - if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) { + if (hotSpotY < 0 || (isScaled ? (int) hotSpotY > bitmap.getHeight() + : hotSpotY >= bitmap.getHeight())) { throw new IllegalArgumentException("y hotspot lies outside of the bitmap area"); } } diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig index 0ef4fa392618..9e2a6cd634de 100644 --- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -1,13 +1,6 @@ package: "com.android.window.flags" flag { - name: "disable_thin_letterboxing_reachability" - namespace: "large_screen_experiences_app_compat" - description: "Whether reachability is disabled in case of thin letterboxing" - bug: "334077350" -} - -flag { name: "disable_thin_letterboxing_policy" namespace: "large_screen_experiences_app_compat" description: "Whether reachability is disabled in case of thin letterboxing" diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt index a59b95a60879..8f36ef000581 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt @@ -40,7 +40,6 @@ fun SettingsTitle(title: String, useMediumWeight: Boolean = false) { Text( text = title, modifier = Modifier.padding(vertical = SettingsDimension.paddingTiny), - color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.titleMedium.withWeight(useMediumWeight), ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index 42d424869b42..d30925935eaf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -936,6 +936,10 @@ public class InternetDialogController implements AccessPointController.AccessPoi mHasActiveSubIdOnDds = false; Log.e(TAG, "Can't get DDS subscriptionInfo"); return; + } else if (ddsSubInfo.isOnlyNonTerrestrialNetwork()) { + mHasActiveSubIdOnDds = false; + Log.d(TAG, "This is NTN, so do not show mobile data"); + return; } mHasActiveSubIdOnDds = isEmbeddedSubscriptionVisible(ddsSubInfo); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt index 4eca51d47a36..56016e151f00 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt @@ -91,12 +91,19 @@ constructor( } else { dismissKeyguard() } - transitionCoordinator?.startExit() + + var transitionOptions: ActivityOptions? = null + if (transitionCoordinator?.decor?.isAttachedToWindow == true) { + transitionCoordinator.startExit() + transitionOptions = options + } if (user == myUserHandle()) { - withContext(mainDispatcher) { context.startActivity(intent, options?.toBundle()) } + withContext(mainDispatcher) { + context.startActivity(intent, transitionOptions?.toBundle()) + } } else { - launchCrossProfileIntent(user, intent, options?.toBundle()) + launchCrossProfileIntent(user, intent, transitionOptions?.toBundle()) } if (overrideTransition) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java index 6a136974b205..9c55bd589443 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java @@ -14,7 +14,9 @@ import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAS import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX; import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN; import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE; + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -1101,6 +1103,34 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { assertThat(mInternetDialogController.hasActiveSubIdOnDds()).isFalse(); } + @Test + public void hasActiveSubIdOnDds_activeDdsAndIsOnlyNonTerrestrialNetwork_returnFalse() { + when(SubscriptionManager.getDefaultDataSubscriptionId()) + .thenReturn(SUB_ID); + SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.isEmbedded()).thenReturn(true); + when(info.isOnlyNonTerrestrialNetwork()).thenReturn(true); + when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); + + mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged(); + + assertFalse(mInternetDialogController.hasActiveSubIdOnDds()); + } + + @Test + public void hasActiveSubIdOnDds_activeDdsAndIsNotOnlyNonTerrestrialNetwork_returnTrue() { + when(SubscriptionManager.getDefaultDataSubscriptionId()) + .thenReturn(SUB_ID); + SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.isEmbedded()).thenReturn(true); + when(info.isOnlyNonTerrestrialNetwork()).thenReturn(false); + when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); + + mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged(); + + assertTrue(mInternetDialogController.hasActiveSubIdOnDds()); + } + private String getResourcesString(String name) { return mContext.getResources().getString(getResourcesId(name)); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 877b90f5e5f7..92f08afc80c4 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1885,7 +1885,6 @@ public class AudioService extends IAudioService.Stub } mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect); - mSoundDoseHelper.reset(); // Restore rotation information. if (mMonitorRotation) { @@ -1896,6 +1895,8 @@ public class AudioService extends IAudioService.Stub // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); + mSoundDoseHelper.reset(/*resetISoundDose=*/true); + sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index 9610034caf01..e28ae952e65a 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -856,11 +856,12 @@ public class SoundDoseHelper { pw.println(); } - /*package*/void reset() { + /*package*/void reset(boolean resetISoundDose) { Log.d(TAG, "Reset the sound dose helper"); - mSoundDose.compareAndExchange(/*expectedValue=*/null, - AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); + if (resetISoundDose) { + mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); + } synchronized (mCsdStateLock) { try { @@ -972,7 +973,7 @@ public class SoundDoseHelper { } } - reset(); + reset(/*resetISoundDose=*/false); } private void onConfigureSafeMedia(boolean force, String caller) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c814a1ef1c13..7625ad8393b5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6267,9 +6267,22 @@ public class PackageManagerService implements PackageSender, TestUtilityService packageStateWrite.setMimeGroup(mimeGroup, mimeTypesSet); }); if (mComponentResolver.updateMimeGroup(snapshotComputer(), packageName, mimeGroup)) { - Binder.withCleanCallingIdentity(() -> - mPreferredActivityHelper.clearPackagePreferredActivities(packageName, - UserHandle.USER_ALL)); + Binder.withCleanCallingIdentity(() -> { + mPreferredActivityHelper.clearPackagePreferredActivities(packageName, + UserHandle.USER_ALL); + // Send the ACTION_PACKAGE_CHANGED when the mimeGroup has changes + final Computer snapShot = snapshotComputer(); + final ArrayList<String> components = new ArrayList<>( + Collections.singletonList(packageName)); + final int appId = packageState.getAppId(); + final int[] userIds = resolveUserIds(UserHandle.USER_ALL); + final String reason = "The mimeGroup is changed"; + for (int i = 0; i < userIds.length; i++) { + final int packageUid = UserHandle.getUid(userIds[i], appId); + mBroadcastHelper.sendPackageChangedBroadcast(snapShot, packageName, + true /* dontKillApp */, components, packageUid, reason); + } + }); } scheduleWriteSettings(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 65d5c0490cfc..78cb8d0f2ace 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -76,7 +76,6 @@ import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON; -import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION; import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; @@ -86,6 +85,7 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM; @@ -311,6 +311,7 @@ import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; @@ -352,6 +353,7 @@ import android.view.RemoteAnimationTarget; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -8533,6 +8535,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isFixedOrientationLetterboxAllowed) { resolveFixedOrientationConfiguration(newParentConfiguration); } + // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds + // are already calculated in resolveFixedOrientationConfiguration. + // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. + if (!isLetterboxedForFixedOrientationAndAspectRatio() + && !mLetterboxUiController.hasFullscreenOverride()) { + resolveAspectRatioRestriction(newParentConfiguration); + } final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); if (compatDisplayInsets != null) { resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets); @@ -8545,14 +8554,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!matchParentBounds()) { computeConfigByResolveHint(resolvedConfig, newParentConfiguration); } - // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds - // are already calculated in resolveFixedOrientationConfiguration, or if in size compat - // mode, it should already be calculated in resolveSizeCompatModeConfiguration. - // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. - } - if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mInSizeCompatModeForBounds - && !mLetterboxUiController.hasFullscreenOverride()) { - resolveAspectRatioRestriction(newParentConfiguration); } if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null @@ -8764,7 +8765,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION; } // Letterbox for limited aspect ratio. - if (mIsAspectRatioApplied) { + if (isLetterboxedForAspectRatioOnly()) { return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO; } @@ -8793,13 +8794,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); final float screenResolvedBoundsWidth = screenResolvedBounds.width(); final float parentAppBoundsWidth = parentAppBounds.width(); + final boolean isImmersiveMode = isImmersiveMode(parentBounds); + final Insets navBarInsets; + if (isImmersiveMode) { + navBarInsets = mDisplayContent.getInsetsStateController() + .getRawInsetsState().calculateInsets( + parentBounds, + WindowInsets.Type.navigationBars(), + true /* ignoreVisibility */); + } else { + navBarInsets = Insets.NONE; + } // Horizontal position int offsetX = 0; if (parentBounds.width() != screenResolvedBoundsWidth) { if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( newParentConfiguration); - offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth + // If in immersive mode, always align to right and overlap right insets (task bar) + // as they are transient and hidden. This removes awkward right spacing. + final int appWidth = (int) (parentAppBoundsWidth + navBarInsets.right); + offsetX = Math.max(0, (int) Math.ceil((appWidth - screenResolvedBoundsWidth) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment @@ -8819,9 +8834,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A newParentConfiguration); // If in immersive mode, always align to bottom and overlap bottom insets (nav bar, // task bar) as they are transient and hidden. This removes awkward bottom spacing. - final float newHeight = mDisplayContent.getDisplayPolicy().isImmersiveMode() - ? parentBoundsHeight : parentAppBoundsHeight; - offsetY = Math.max(0, (int) Math.ceil((newHeight + final int appHeight = (int) (parentAppBoundsHeight + navBarInsets.bottom); + offsetY = Math.max(0, (int) Math.ceil((appHeight - screenResolvedBoundsHeight) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment @@ -8841,7 +8855,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the top is aligned with parentAppBounds add the vertical insets back so that the app // content aligns with the status bar - if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) { + if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top + && !isImmersiveMode) { resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top; if (mSizeCompatBounds != null) { mSizeCompatBounds.top = parentBounds.top; @@ -8864,6 +8879,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + boolean isImmersiveMode(@NonNull Rect parentBounds) { + if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds) { + return false; + } + final Insets navBarInsets = mDisplayContent.getInsetsStateController() + .getRawInsetsState().calculateInsets( + parentBounds, + WindowInsets.Type.navigationBars(), + false /* ignoreVisibility */); + return Insets.NONE.equals(navBarInsets); + } + @NonNull Rect getScreenResolvedBounds() { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); @@ -8906,6 +8933,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mLetterboxBoundsForFixedOrientationAndAspectRatio != null; } + boolean isLetterboxedForAspectRatioOnly() { + return mLetterboxBoundsForAspectRatio != null; + } + boolean isAspectRatioApplied() { return mIsAspectRatioApplied; } @@ -9198,11 +9229,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // orientation bounds (stored in resolved bounds) instead of parent bounds since the // activity will be displayed within them even if it is in size compat mode. They should be // saved here before resolved bounds are overridden below. - final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio() + final Rect containerBounds = isAspectRatioApplied() ? new Rect(resolvedBounds) : newParentConfiguration.windowConfiguration.getBounds(); - final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio() - ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds()) + final Rect containerAppBounds = isAspectRatioApplied() + ? new Rect(resolvedConfig.windowConfiguration.getAppBounds()) : newParentConfiguration.windowConfiguration.getAppBounds(); final int requestedOrientation = getRequestedConfigurationOrientation(); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 691176a794ae..7192a20935da 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -1686,7 +1686,7 @@ final class LetterboxUiController { if (mainWin.isLetterboxedForDisplayCutout()) { return "DISPLAY_CUTOUT"; } - if (mActivityRecord.isAspectRatioApplied()) { + if (mActivityRecord.isLetterboxedForAspectRatioOnly()) { return "ASPECT_RATIO"; } return "UNKNOWN_REASON"; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b6760c55c0cd..944b82112482 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5793,7 +5793,7 @@ class Task extends TaskFragment { // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the // current task to be selected. - if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) { + if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) { ActivityRecord next = topRunningActivity(null, task.mTaskId); if (next == null) { next = topRunningActivity(null, INVALID_TASK_ID); @@ -5837,6 +5837,15 @@ class Task extends TaskFragment { + tr.mTaskId); if (mTransitionController.isShellTransitionsEnabled()) { + // TODO(b/277838915): Consider to make it concurrent to eliminate the special case. + final Transition collecting = mTransitionController.getCollectingTransition(); + if (collecting != null && collecting.mType == TRANSIT_OPEN) { + // It can be a CLOSING participate of an OPEN transition. This avoids the deferred + // transition from moving task to back after the task was moved to front. + collecting.collect(tr); + moveTaskToBackInner(tr, collecting); + return true; + } final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); // Guarantee that this gets its own transition by queueing on SyncEngine @@ -5865,7 +5874,7 @@ class Task extends TaskFragment { return true; } - private boolean moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) { + private void moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) { final Transition.ReadyCondition movedToBack = new Transition.ReadyCondition("moved-to-back", task); if (transition != null) { @@ -5880,7 +5889,7 @@ class Task extends TaskFragment { if (inPinnedWindowingMode()) { mTaskSupervisor.removeRootTask(this); - return true; + return; } mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, @@ -5903,7 +5912,6 @@ class Task extends TaskFragment { } else { mRootWindowContainer.resumeFocusedTasksTopActivities(); } - return true; } boolean willActivityBeVisible(IBinder token) { diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index bf15bc89be97..c6476df1e3c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -108,6 +108,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.view.InsetsFrameProvider; @@ -123,6 +124,7 @@ import com.android.internal.policy.SystemBarUtils; import com.android.internal.statusbar.LetterboxDetails; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.DeviceStateController.DeviceState; +import com.android.window.flags.Flags; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -187,6 +189,7 @@ public class SizeCompatTests extends WindowTestsBase { private void setUpApp(DisplayContent display) { mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); mActivity = mTask.getTopNonFinishingActivity(); + doReturn(false).when(mActivity).isImmersiveMode(any()); } private void setUpDisplaySizeWithApp(int dw, int dh) { @@ -395,6 +398,55 @@ public class SizeCompatTests extends WindowTestsBase { verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); } + // TODO(b/333663877): Enable test after fix + @Test + @RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION}) + public void testRepositionLandscapeImmersiveAppWithDisplayCutout() { + final int dw = 2100; + final int dh = 2000; + final int cutoutHeight = 150; + final TestDisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh) + .setCanRotate(false) + .setNotch(cutoutHeight) + .build(); + setUpApp(display); + display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); + mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); + + doReturn(true).when(mActivity).isImmersiveMode(any()); + prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, + SCREEN_ORIENTATION_LANDSCAPE); + addWindowToActivity(mActivity); + mActivity.mRootWindowContainer.performSurfacePlacement(); + + final Function<ActivityRecord, Rect> innerBoundsOf = + (ActivityRecord a) -> { + final Rect bounds = new Rect(); + a.mLetterboxUiController.getLetterboxInnerBounds(bounds); + return bounds; + }; + + final Consumer<Integer> doubleClick = + (Integer y) -> { + mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); + mActivity.mRootWindowContainer.performSurfacePlacement(); + }; + + final Rect bounds = mActivity.getBounds(); + assertTrue(bounds.top > cutoutHeight && bounds.bottom < dh); + assertEquals(dw, bounds.width()); + + // Double click bottom. + doubleClick.accept(dh - 10); + assertEquals(dh, innerBoundsOf.apply(mActivity).bottom); + + // Double click top. + doubleClick.accept(10); + doubleClick.accept(10); + assertEquals(cutoutHeight, innerBoundsOf.apply(mActivity).top); + } + @Test public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); @@ -3994,8 +4046,7 @@ public class SizeCompatTests extends WindowTestsBase { // Prepare unresizable landscape activity prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); - final DisplayPolicy displayPolicy = mActivity.mDisplayContent.getDisplayPolicy(); - doReturn(immersive).when(displayPolicy).isImmersiveMode(); + doReturn(immersive).when(mActivity).isImmersiveMode(any()); mActivity.mRootWindowContainer.performSurfacePlacement(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index f76491afe008..4994d6a2bb3f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -64,8 +64,10 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -2373,9 +2375,7 @@ public class TransitionTests extends WindowTestsBase { assertTrue(transitA.isCollecting()); // finish collecting A - transitA.start(); - transitA.setAllReady(); - mSyncEngine.tryFinishForTest(transitA.getSyncId()); + tryFinishTransitionSyncSet(transitA); waitUntilHandlersIdle(); assertTrue(transitA.isPlaying()); @@ -2481,6 +2481,36 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testDeferredMoveTaskToBack() { + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Task task = activity.getTask(); + registerTestTransitionPlayer(); + final TransitionController controller = mWm.mRoot.mTransitionController; + mSyncEngine = createTestBLASTSyncEngine(); + controller.setSyncEngine(mSyncEngine); + final Transition transition = createTestTransition(TRANSIT_CHANGE, controller); + controller.moveToCollecting(transition); + task.moveTaskToBack(task); + // Actual action will be deferred by current transition. + verify(task, never()).moveToBack(any(), any()); + + tryFinishTransitionSyncSet(transition); + waitUntilHandlersIdle(); + // Continue to move task to back after the transition is done. + verify(task).moveToBack(any(), any()); + final Transition moveBackTransition = controller.getCollectingTransition(); + assertNotNull(moveBackTransition); + moveBackTransition.abort(); + + // The move-to-back can be collected in to a collecting OPEN transition. + clearInvocations(task); + final Transition transition2 = createTestTransition(TRANSIT_OPEN, controller); + controller.moveToCollecting(transition2); + task.moveTaskToBack(task); + verify(task).moveToBack(any(), any()); + } + + @Test public void testNoSyncFlagIfOneTrack() { final TransitionController controller = mAtm.getTransitionController(); final TestTransitionPlayer player = registerTestTransitionPlayer(); @@ -2497,17 +2527,11 @@ public class TransitionTests extends WindowTestsBase { controller.startCollectOrQueue(transitC, (deferred) -> {}); // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag - transitA.start(); - transitA.setAllReady(); - mSyncEngine.tryFinishForTest(transitA.getSyncId()); + tryFinishTransitionSyncSet(transitA); assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0); - transitB.start(); - transitB.setAllReady(); - mSyncEngine.tryFinishForTest(transitB.getSyncId()); + tryFinishTransitionSyncSet(transitB); assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0); - transitC.start(); - transitC.setAllReady(); - mSyncEngine.tryFinishForTest(transitC.getSyncId()); + tryFinishTransitionSyncSet(transitC); assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0); } @@ -2616,6 +2640,12 @@ public class TransitionTests extends WindowTestsBase { assertEquals("reason1", condition1.mAlternate); } + private void tryFinishTransitionSyncSet(Transition transition) { + transition.setAllReady(); + transition.start(); + mSyncEngine.tryFinishForTest(transition.getSyncId()); + } + private static void makeTaskOrganized(Task... tasks) { final ITaskOrganizer organizer = mock(ITaskOrganizer.class); for (Task t : tasks) { |