diff options
7 files changed, 180 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 33af563bd954..31f30afd073b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2374,7 +2374,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // IME parent may failed to attach to the app during rotating the screen. // See DisplayContent#shouldImeAttachedToApp, DisplayContent#isImeControlledByApp if (windowConfigChanged) { - getDisplayContent().updateImeControlTarget(); + // If the window was the IME layering target, updates the IME surface parent in case + // the IME surface may be wrongly positioned when the window configuration affects the + // IME surface association. (e.g. Attach IME surface on the display instead of the + // app when the app bounds being letterboxed.) + mDisplayContent.updateImeControlTarget(isImeLayeringTarget() /* updateImeParent */); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 1f60e79ee5eb..d3e5a8a8e842 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -1145,7 +1145,9 @@ public class WindowStateTests extends WindowTestsBase { spyOn(app.getDisplayContent()); app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN); - verify(app.getDisplayContent()).updateImeControlTarget(); + // Expect updateImeParent will be invoked when the configuration of the IME control + // target has changed. + verify(app.getDisplayContent()).updateImeControlTarget(eq(true) /* updateImeParent */); assertEquals(mAppWindow, mDisplayContent.getImeTarget(IME_TARGET_CONTROL).getWindow()); } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt index b7eea1b58485..fed953c92a73 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt @@ -119,4 +119,17 @@ constructor( } return false } + + fun toggleFixPortraitOrientation(wmHelper: WindowManagerStateHelper) { + val button = uiDevice.wait(Until.findObject(By.res(getPackage(), + "toggle_fixed_portrait_btn")), FIND_TIMEOUT) + require(button != null) { + "Button not found, this usually happens when the device " + + "was left in an unknown state (e.g. Screen turned off)" + } + button.click() + mInstrumentation.waitForIdleSync() + // Ensure app relaunching transition finish and the IME has shown + waitIMEShown(wmHelper) + } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt new file mode 100644 index 000000000000..806ce99b6d81 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.wm.flicker.ime + +import android.platform.test.annotations.Postsubmit +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.BaseTest +import com.android.server.wm.flicker.FlickerBuilder +import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTest +import com.android.server.wm.flicker.FlickerTestFactory +import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.traces.region.RegionSubject +import com.android.server.wm.traces.common.ComponentNameMatcher +import com.android.server.wm.traces.common.service.PlatformConsts +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test IME window shown on the app with fixing portrait orientation. + * To run this test: `atest FlickerTests:OpenImeWindowToFixedPortraitAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class OpenImeWindowToFixedPortraitAppTest(flicker: FlickerTest) : BaseTest(flicker) { + private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation) + + /** {@inheritDoc} */ + override val transition: FlickerBuilder.() -> Unit = { + setup { + testApp.launchViaIntent(wmHelper) + testApp.openIME(wmHelper) + // Enable letterbox when the app calls setRequestedOrientation + device.executeShellCommand("cmd window set-ignore-orientation-request true") + } + transitions { + testApp.toggleFixPortraitOrientation(wmHelper) + } + teardown { + testApp.exit() + device.executeShellCommand("cmd window set-ignore-orientation-request false") + } + } + + @Postsubmit + @Test + fun imeLayerVisibleStart() { + flicker.assertLayersStart { + this.isVisible(ComponentNameMatcher.IME) + } + } + + @Postsubmit + @Test + fun imeLayerExistsEnd() { + flicker.assertLayersEnd { + this.isVisible(ComponentNameMatcher.IME) + } + } + + @Postsubmit + @Test + fun imeLayerVisibleRegionKeepsTheSame() { + var imeLayerVisibleRegionBeforeTransition: RegionSubject? = null + flicker.assertLayersStart { + imeLayerVisibleRegionBeforeTransition = this.visibleRegion(ComponentNameMatcher.IME) + } + flicker.assertLayersEnd { + this.visibleRegion(ComponentNameMatcher.IME) + .coversExactly(imeLayerVisibleRegionBeforeTransition!!.region) + } + } + + @Postsubmit + @Test + fun appWindowWithLetterboxCoversExactlyOnScreen() { + val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation) + flicker.assertLayersEnd { + this.visibleRegion(testApp.or(ComponentNameMatcher.LETTERBOX)) + .coversExactly(displayBounds) + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTest> { + return FlickerTestFactory.nonRotationTests( + supportedRotations = listOf( + PlatformConsts.Rotation.ROTATION_90, + ), + supportedNavigationModes = listOf( + PlatformConsts.NavBar.MODE_3BUTTON, + PlatformConsts.NavBar.MODE_GESTURAL + ) + ) + } + } +}
\ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index 83823eae993b..cd47f6039abf 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -47,7 +47,7 @@ android:theme="@style/CutoutShortEdges" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus" android:windowSoftInputMode="stateVisible" - android:configChanges="orientation|screenSize" + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:label="ImeAppAutoFocus" android:exported="true"> <intent-filter> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml index baaf7073b3a6..fa73e2c63780 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml @@ -26,14 +26,27 @@ android:layout_width="match_parent" android:imeOptions="flagNoExtractUi" android:inputType="text"/> - <Button - android:id="@+id/finish_activity_btn" + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="Finish activity" /> - <Button - android:id="@+id/start_dialog_themed_activity_btn" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="Start dialog themed activity" /> + android:layout_height="match_parent" + android:orientation="horizontal"> + <Button + android:id="@+id/finish_activity_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Finish activity" /> + <Button + android:id="@+id/start_dialog_themed_activity_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Dialog themed activity" /> + <ToggleButton + android:id="@+id/toggle_fixed_portrait_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textOn="Portrait (On)" + android:textOff="Portrait (Off)" + /> + </LinearLayout> </LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java index bb200f125507..7ee8debddcf1 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java @@ -16,21 +16,29 @@ package com.android.server.wm.flicker.testapp; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + import android.content.Intent; import android.widget.Button; import android.widget.EditText; +import android.widget.ToggleButton; public class ImeActivityAutoFocus extends ImeActivity { - @Override protected void onStart() { super.onStart(); - EditText editTextField = findViewById(R.id.plain_text_input); - editTextField.requestFocus(); - Button startThemedActivityButton = findViewById(R.id.start_dialog_themed_activity_btn); startThemedActivityButton.setOnClickListener( button -> startActivity(new Intent(this, DialogThemedActivity.class))); + + ToggleButton toggleFixedPortraitButton = findViewById(R.id.toggle_fixed_portrait_btn); + toggleFixedPortraitButton.setOnCheckedChangeListener( + (button, isChecked) -> setRequestedOrientation( + isChecked ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_UNSPECIFIED)); + + EditText editTextField = findViewById(R.id.plain_text_input); + editTextField.requestFocus(); } } |