diff options
4 files changed, 71 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 89315d1422c7..78199d4412a6 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -582,6 +582,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } } + // Changes in opening apps and closing apps may cause orientation change. + reportDescendantOrientationChangeIfNeeded(); return; } @@ -729,11 +731,31 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } SurfaceControl.closeTransaction(); } + + // Visibility changes may cause orientation request change. + reportDescendantOrientationChangeIfNeeded(); } return delayed; } + private void reportDescendantOrientationChangeIfNeeded() { + // Orientation request is exposed only when we're visible. Therefore visibility change + // will change requested orientation. Notify upward the hierarchy ladder to adjust + // configuration. This is important to cases where activities with incompatible + // orientations launch, or user goes back from an activity of bi-orientation to an + // activity with specified orientation. + if (mActivityRecord.getRequestedConfigurationOrientation() == getConfiguration().orientation + || getOrientationIgnoreVisibility() == SCREEN_ORIENTATION_UNSET) { + return; + } + + final IBinder freezeToken = + mActivityRecord.mayFreezeScreenLocked(mActivityRecord.app) + ? mActivityRecord.appToken : null; + onDescendantOrientationChanged(freezeToken, mActivityRecord); + } + /** * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns * true. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 888d74163163..499cbaf915a1 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -330,7 +330,7 @@ class Task extends WindowContainer<AppWindowToken> implements ConfigurationConta // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill // it if possible. // TODO: Move to TaskRecord after unification is done. - if (mTaskRecord != null) { + if (mTaskRecord != null && mTaskRecord.getParent() != null) { mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration()); return true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 2c575f59a020..68b40b92b9cc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -18,11 +18,11 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; @@ -42,12 +42,16 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.verify; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.Display; import android.view.Surface; import android.view.WindowManager; @@ -55,6 +59,7 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; /** * Tests for the {@link AppWindowToken} class. @@ -332,6 +337,46 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + public void testReportOrientationChangeOnVisibilityChange() { + synchronized (mWm.mGlobalLock) { + mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + + mDisplayContent.getDisplayRotation().setFixedToUserRotation( + DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED); + + doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord) + .getRequestedConfigurationOrientation(); + + mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS); + mToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + } + + verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class)); + } + + @Test + public void testReportOrientationChangeOnOpeningClosingAppChange() { + synchronized (mWm.mGlobalLock) { + mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + + mDisplayContent.getDisplayRotation().setFixedToUserRotation( + DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED); + mDisplayContent.getDisplayInfo().state = Display.STATE_ON; + mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_CLOSE, + false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); + + doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord) + .getRequestedConfigurationOrientation(); + + mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS); + mToken.setVisibility(false, false); + } + + verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class)); + } + + @Test public void testCreateRemoveStartingWindow() { mToken.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index da1defabeaaf..0dec8ee7776f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -82,6 +82,8 @@ class WindowTestUtils { }, new ComponentName("", ""), false, dc, true /* fillsParent */); mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT; mSkipOnParentChanged = skipOnParentChanged; + mActivityRecord = mock(ActivityRecord.class); + mActivityRecord.app = mock(WindowProcessController.class); } int getWindowsCount() { |