diff options
23 files changed, 204 insertions, 35 deletions
diff --git a/apex/extservices/apex_manifest.json b/apex/extservices/apex_manifest.json index 4ac3f779166f..fd6c01b939a7 100644 --- a/apex/extservices/apex_manifest.json +++ b/apex/extservices/apex_manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.extservices", - "version": 300900400 + "version": 300900500 } diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json index 69870534cf36..1806fc4249c4 100644 --- a/apex/permission/apex_manifest.json +++ b/apex/permission/apex_manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.permission", - "version": 300900400 + "version": 300900500 } diff --git a/apex/statsd/apex_manifest.json b/apex/statsd/apex_manifest.json index 820d3039f17a..0616cd6f552d 100644 --- a/apex/statsd/apex_manifest.json +++ b/apex/statsd/apex_manifest.json @@ -1,5 +1,5 @@ { "name": "com.android.os.statsd", - "version": 300900400 + "version": 300900500 } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index b6e4e1628c20..d7cc11b7fd15 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -242,7 +242,8 @@ public class PipTouchHandler { this::updateMovementBounds, sysUiState); mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler, () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(), - true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle())); + true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()), + menuController::hideMenu); Resources res = context.getResources(); mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge); @@ -708,6 +709,7 @@ public class PipTouchHandler { // on and changing MotionEvents into HoverEvents. // Let's not enable menu show/hide for a11y services. if (!mAccessibilityManager.isTouchExplorationEnabled()) { + mTouchState.removeHoverExitTimeoutCallback(); mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(), false /* allowMenuTimeout */, false /* willResizeMenu */, shouldShowResizeHandle()); @@ -725,7 +727,7 @@ public class PipTouchHandler { // Let's not enable menu show/hide for a11y services. if (!mAccessibilityManager.isTouchExplorationEnabled()) { mHideMenuAfterShown = true; - mMenuController.hideMenu(); + mTouchState.scheduleHoverExitTimeoutCallback(); } if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) { sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java index 132c04d381dd..ecd1128a5680 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java @@ -36,10 +36,12 @@ public class PipTouchState { @VisibleForTesting static final long DOUBLE_TAP_TIMEOUT = 200; + static final long HOVER_EXIT_TIMEOUT = 50; private final Handler mHandler; private final ViewConfiguration mViewConfig; private final Runnable mDoubleTapTimeoutCallback; + private final Runnable mHoverExitTimeoutCallback; private VelocityTracker mVelocityTracker; private long mDownTouchTime = 0; @@ -64,10 +66,11 @@ public class PipTouchState { private int mActivePointerId; public PipTouchState(ViewConfiguration viewConfig, Handler handler, - Runnable doubleTapTimeoutCallback) { + Runnable doubleTapTimeoutCallback, Runnable hoverExitTimeoutCallback) { mViewConfig = viewConfig; mHandler = handler; mDoubleTapTimeoutCallback = doubleTapTimeoutCallback; + mHoverExitTimeoutCallback = hoverExitTimeoutCallback; } /** @@ -197,6 +200,10 @@ public class PipTouchState { recycleVelocityTracker(); break; } + case MotionEvent.ACTION_BUTTON_PRESS: { + removeHoverExitTimeoutCallback(); + break; + } } } @@ -326,6 +333,15 @@ public class PipTouchState { mHandler.removeCallbacks(mDoubleTapTimeoutCallback); } + void scheduleHoverExitTimeoutCallback() { + mHandler.removeCallbacks(mHoverExitTimeoutCallback); + mHandler.postDelayed(mHoverExitTimeoutCallback, HOVER_EXIT_TIMEOUT); + } + + void removeHoverExitTimeoutCallback() { + mHandler.removeCallbacks(mHoverExitTimeoutCallback); + } + void addMovementToVelocityTracker(MotionEvent event) { if (mVelocityTracker == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 51eca67e02f9..afc5be4e6c2f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -265,9 +265,13 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic private void createDialog() { final boolean isDeviceManaged = mSecurityController.isDeviceManaged(); + boolean isProfileOwnerOfOrganizationOwnedDevice = + mSecurityController.isProfileOwnerOfOrganizationOwnedDevice(); final boolean hasWorkProfile = mSecurityController.hasWorkProfile(); final CharSequence deviceOwnerOrganization = mSecurityController.getDeviceOwnerOrganizationName(); + final CharSequence workProfileOrganizationName = + mSecurityController.getWorkProfileOrganizationName(); final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser(); final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile(); final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled(); @@ -284,7 +288,8 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic // device management section CharSequence managementMessage = getManagementMessage(isDeviceManaged, - deviceOwnerOrganization); + deviceOwnerOrganization, isProfileOwnerOfOrganizationOwnedDevice, + workProfileOrganizationName); if (managementMessage == null) { dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.GONE); } else { @@ -292,7 +297,11 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic TextView deviceManagementWarning = (TextView) dialogView.findViewById(R.id.device_management_warning); deviceManagementWarning.setText(managementMessage); - mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this); + // Don't show the policies button for profile owner of org owned device, because there + // is no policies settings screen for it + if (!isProfileOwnerOfOrganizationOwnedDevice) { + mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this); + } } // ca certificate section @@ -382,11 +391,18 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic } protected CharSequence getManagementMessage(boolean isDeviceManaged, - CharSequence organizationName) { - if (!isDeviceManaged) return null; - if (organizationName != null) + CharSequence organizationName, boolean isProfileOwnerOfOrganizationOwnedDevice, + CharSequence workProfileOrganizationName) { + if (!isDeviceManaged && !isProfileOwnerOfOrganizationOwnedDevice) { + return null; + } + if (isDeviceManaged && organizationName != null) { return mContext.getString( R.string.monitoring_description_named_management, organizationName); + } else if (isProfileOwnerOfOrganizationOwnedDevice && workProfileOrganizationName != null) { + return mContext.getString( + R.string.monitoring_description_named_management, workProfileOrganizationName); + } return mContext.getString(R.string.monitoring_description_management); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java index 3155e57d8ab3..17b2e3225200 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchStateTest.java @@ -16,6 +16,7 @@ package com.android.systemui.pip.phone; +import static android.view.MotionEvent.ACTION_BUTTON_PRESS; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; @@ -49,13 +50,17 @@ public class PipTouchStateTest extends SysuiTestCase { private PipTouchState mTouchState; private CountDownLatch mDoubleTapCallbackTriggeredLatch; + private CountDownLatch mHoverExitCallbackTriggeredLatch; @Before public void setUp() throws Exception { mDoubleTapCallbackTriggeredLatch = new CountDownLatch(1); + mHoverExitCallbackTriggeredLatch = new CountDownLatch(1); mTouchState = new PipTouchState(ViewConfiguration.get(getContext()), Handler.createAsync(Looper.myLooper()), () -> { mDoubleTapCallbackTriggeredLatch.countDown(); + }, () -> { + mHoverExitCallbackTriggeredLatch.countDown(); }); assertFalse(mTouchState.isDoubleTap()); assertFalse(mTouchState.isWaitingForDoubleTap()); @@ -120,6 +125,35 @@ public class PipTouchStateTest extends SysuiTestCase { assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1); } + @Test + public void testHoverExitTimeout_timeoutCallbackCalled() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + + // TODO: Remove this sleep. Its only being added because it speeds up this test a bit. + Thread.sleep(50); + TestableLooper.get(this).processAllMessages(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 0); + } + + @Test + public void testHoverExitTimeout_timeoutCallbackNotCalled() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + TestableLooper.get(this).processAllMessages(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1); + } + + @Test + public void testHoverExitTimeout_timeoutCallbackNotCalled_ifButtonPress() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + mTouchState.onTouchEvent(createMotionEvent(ACTION_BUTTON_PRESS, SystemClock.uptimeMillis(), + 0, 0)); + + // TODO: Remove this sleep. Its only being added because it speeds up this test a bit. + Thread.sleep(50); + TestableLooper.get(this).processAllMessages(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1); + } + private MotionEvent createMotionEvent(int action, long eventTime, float x, float y) { return MotionEvent.obtain(0, eventTime, action, x, y, 0); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index ea5449b4448e..417b19f0cfc1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -367,13 +367,46 @@ public class QSSecurityFooterTest extends SysuiTestCase { } @Test - public void testGetManagementMessage() { - assertEquals(null, mFooter.getManagementMessage(false, MANAGING_ORGANIZATION)); + public void testGetManagementMessage_noManagement() { + assertEquals(null, mFooter.getManagementMessage( + /* isDeviceManaged= */ false, + MANAGING_ORGANIZATION, + /* isProfileOwnerOfOrganizationOwnedDevice= */ false, + MANAGING_ORGANIZATION)); + } + + @Test + public void testGetManagementMessage_deviceOwner() { assertEquals(mContext.getString(R.string.monitoring_description_named_management, MANAGING_ORGANIZATION), - mFooter.getManagementMessage(true, MANAGING_ORGANIZATION)); + mFooter.getManagementMessage( + /* isDeviceManaged= */ true, + MANAGING_ORGANIZATION, + /* isProfileOwnerOfOrganizationOwnedDevice= */ false, + /* workProfileOrganizationName= */ null)); + assertEquals(mContext.getString(R.string.monitoring_description_management), + mFooter.getManagementMessage( + /* isDeviceManaged= */ true, + /* organizationName= */ null, + /* isProfileOwnerOfOrganizationOwnedDevice= */ false, + /* workProfileOrganizationName= */ null)); + } + + @Test + public void testGetManagementMessage_profileOwnerOfOrganizationOwnedDevice() { + assertEquals(mContext.getString(R.string.monitoring_description_named_management, + MANAGING_ORGANIZATION), + mFooter.getManagementMessage( + /* isDeviceManaged= */ false, + /* organizationName= */ null, + /* isProfileOwnerOfOrganizationOwnedDevice= */ true, + MANAGING_ORGANIZATION)); assertEquals(mContext.getString(R.string.monitoring_description_management), - mFooter.getManagementMessage(true, null)); + mFooter.getManagementMessage( + /* isDeviceManaged= */ false, + /* organizationName= */ null, + /* isProfileOwnerOfOrganizationOwnedDevice= */ true, + /* workProfileOrganizationName= */ null)); } @Test diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json index d747cc882f0d..c1a5b05fc9d9 100644 --- a/packages/Tethering/apex/manifest.json +++ b/packages/Tethering/apex/manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.tethering", - "version": 300900400 + "version": 300900500 } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a38d42b92600..a2f76e99810c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6334,6 +6334,9 @@ public class ActivityManagerService extends IActivityManager.Stub int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk, int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) { + if (mInternal.isPendingTopUid(uid)) { + return ActivityManager.APP_START_MODE_NORMAL; + } UidRecord uidRec = mProcessList.getUidRecordLocked(uid); if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg=" + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle=" diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 8f0de7312ee5..db4c3ea4cf06 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -954,8 +954,6 @@ class ActivityStack extends Task { void awakeFromSleepingLocked() { // Ensure activities are no longer sleeping. forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false)); - ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, - false /* preserveWindows */); if (mPausingActivity != null) { Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause"); mPausingActivity.activityPaused(true); @@ -2058,7 +2056,12 @@ class ActivityStack extends Task { if (r.mLaunchTaskBehind) { transit = TRANSIT_TASK_OPEN_BEHIND; } else if (getDisplay().isSingleTaskInstance()) { + // If a new task is being launched in a single task display, we don't need + // to play normal animation, but need to trigger a callback when an app + // transition is actually handled. So ignore already prepared activity, and + // override it. transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY; + keepCurTransition = false; } else { // If a new task is being launched, then mark the existing top activity as // supporting picture-in-picture while pausing only if the starting activity diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 8260cb31acda..2be3acc52058 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -253,6 +253,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { req = mLastKeyguardForcedOrientation; } } + mLastOrientationSource = win; return req; } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c56440785bba..2da2c2980231 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1189,6 +1189,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo activity.onRemovedFromDisplay(); if (activity == mFixedRotationLaunchingApp) { + // Make sure the states of associated tokens are also cleared. + activity.finishFixedRotationTransform(); setFixedRotationLaunchingAppUnchecked(null); } } @@ -1487,6 +1489,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // window was transferred ({@link #mSkipAppTransitionAnimation}). return false; } + if ((mAppTransition.getTransitFlags() + & WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) { + // The transition may be finished before keyguard hidden. In order to avoid the + // intermediate orientation change, it is more stable to freeze the display. + return false; + } } else if (r != topRunningActivity()) { // If the transition has not started yet, the activity must be the top. return false; @@ -2310,6 +2318,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void onAppTransitionDone() { super.onAppTransitionDone(); mWmService.mWindowsChanged = true; + // If the transition finished callback cannot match the token for some reason, make sure the + // rotated state is cleared if it is already invisible. + if (mFixedRotationLaunchingApp != null && !mFixedRotationLaunchingApp.mVisibleRequested + && !mFixedRotationLaunchingApp.isVisible() + && !mDisplayRotation.isRotatingSeamlessly()) { + clearFixedRotationLaunchingApp(); + } } @Override @@ -3011,11 +3026,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ScreenRotationAnimation rotationAnimation = getRotationAnimation(); if (rotationAnimation != null) { - pw.print(subPrefix); pw.println(" mScreenRotationAnimation:"); - rotationAnimation.printTo(" ", pw); + rotationAnimation.printTo(subPrefix, pw); } else if (dumpAll) { - pw.print(subPrefix); pw.println(" no ScreenRotationAnimation "); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 119b188dfa00..c7ffc067427d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2391,6 +2391,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // activity here. resumeFocusedStacksTopActivities(); } + // The visibility update must not be called before resuming the top, so the + // display orientation can be updated first if needed. Otherwise there may + // have redundant configuration changes due to apply outdated display + // orientation (from keyguard) to activity. + stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + false /* preserveWindows */); } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c664a841fc1f..6785127d5953 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1423,7 +1423,7 @@ class Task extends WindowContainer<WindowContainer> { void removeChild(WindowContainer r, String reason) { // A rootable child task that is now being removed from an organized task. Making sure // the stack references is keep updated. - if (mTaskOrganizer != null && mCreatedByOrganizer && r.asTask() != null) { + if (mCreatedByOrganizer && r.asTask() != null) { getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) r); } if (!mChildren.contains(r)) { diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index c3acb16dda49..79f3b8340b21 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1864,14 +1864,14 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { pw.println(prefix + "TaskDisplayArea " + getName()); - super.dump(pw, prefix, dumpAll); + final String doublePrefix = prefix + " "; + super.dump(pw, doublePrefix, dumpAll); if (mPreferredTopFocusableStack != null) { - pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); + pw.println(doublePrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); } if (mLastFocusedStack != null) { - pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack); + pw.println(doublePrefix + "mLastFocusedStack=" + mLastFocusedStack); } - final String doublePrefix = prefix + " "; final String triplePrefix = doublePrefix + " "; pw.println(doublePrefix + "Application tokens in top down Z order:"); for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f984a8b024c1..0ade5867d059 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2555,6 +2555,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< pw.print(prefix); pw.println("ContainerAnimator:"); mSurfaceAnimator.dump(pw, prefix + " "); } + if (mLastOrientationSource != null) { + pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource); + } } final void updateSurfacePosition() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 668f04785bbc..c7b45efb2de1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -127,8 +127,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mTask = mStack.getBottomMostTask(); mActivity = mTask.getTopNonFinishingActivity(); - doReturn(false).when(mService).isBooting(); - doReturn(true).when(mService).isBooted(); + setBooted(mService); } @Test @@ -1535,7 +1534,7 @@ public class ActivityRecordTests extends ActivityTestsBase { * Sets orientation without notifying the parent to simulate that the display has not applied * the requested orientation yet. */ - private static void setRotatedScreenOrientationSilently(ActivityRecord r) { + static void setRotatedScreenOrientationSilently(ActivityRecord r) { final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT ? SCREEN_ORIENTATION_LANDSCAPE : SCREEN_ORIENTATION_PORTRAIT; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 37882bb2ba76..1b42a0466cf7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1392,8 +1392,7 @@ public class ActivityStackTests extends ActivityTestsBase { } mSupervisor.endDeferResume(); - doReturn(false).when(mService).isBooting(); - doReturn(true).when(mService).isBooted(); + setBooted(mService); // 2 activities are started while keyguard is locked, so they are waiting to be resolved. assertFalse(unknownAppVisibilityController.allResolved()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 64b5eca1beb8..f65d6e0c82af 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -67,8 +67,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - doReturn(false).when(mService).isBooting(); - doReturn(true).when(mService).isBooted(); + setBooted(mService); } /** Verify that activity is finished correctly upon request. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index ddb186a1d2da..23029017bac9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1239,8 +1239,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testNoFixedRotationWithPip() { // Make resume-top really update the activity state. - doReturn(false).when(mWm.mAtmService).isBooting(); - doReturn(true).when(mWm.mAtmService).isBooted(); + setBooted(mWm.mAtmService); // Speed up the test by a few seconds. mWm.mAtmService.deferWindowLayout(); doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 5dba00455913..51db099676b0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -42,6 +42,7 @@ import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -57,8 +58,10 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.platform.test.annotations.Presubmit; +import android.util.MergedConfiguration; import android.util.Pair; import androidx.test.filters.MediumTest; @@ -221,6 +224,35 @@ public class RootActivityContainerTests extends ActivityTestsBase { null /* target */, null /* targetOptions */); } + @Test + public void testAwakeFromSleepingWithAppConfiguration() { + final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true).build(); + activity.moveFocusableActivityToTop("test"); + assertTrue(activity.getStack().isFocusedStackOnDisplay()); + ActivityRecordTests.setRotatedScreenOrientationSilently(activity); + + final Configuration rotatedConfig = new Configuration(); + display.computeScreenConfiguration(rotatedConfig, display.getDisplayRotation() + .rotationForOrientation(activity.getOrientation(), display.getRotation())); + assertNotEquals(activity.getConfiguration().orientation, rotatedConfig.orientation); + // Assume the activity was shown in different orientation. For example, the top activity is + // landscape and the portrait lockscreen is shown. + activity.setLastReportedConfiguration( + new MergedConfiguration(mService.getGlobalConfiguration(), rotatedConfig)); + activity.setState(ActivityState.STOPPED, "sleep"); + + display.setIsSleeping(true); + doReturn(false).when(display).shouldSleep(); + // Allow to resume when awaking. + setBooted(mService); + mRootWindowContainer.applySleepTokens(true); + + // The display orientation should be changed by the activity so there is no relaunch. + verify(activity, never()).relaunchActivityLocked(anyBoolean()); + assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation); + } + /** * Verifies that removal of activity with task and stack is done correctly. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java index d7462f810bb7..53c2a5b8967d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import android.os.Handler; import android.testing.DexmakerShareClassLoaderRule; @@ -67,6 +69,15 @@ class SystemServiceTestsBase { } /** + * Make the system booted, so that {@link ActivityStack#resumeTopActivityInnerLocked} can really + * be executed to update activity state and configuration when resuming the current top. + */ + static void setBooted(ActivityTaskManagerService atmService) { + doReturn(false).when(atmService).isBooting(); + doReturn(true).when(atmService).isBooted(); + } + + /** * Utility class to compare the output of T#toString. It is convenient to have readable output * of assertion if the string content can represent the expected states. */ |