Merge "Fix IME snapshot applied on non-IME input target window"
This commit is contained in:
@@ -3987,11 +3987,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
if (target == mImeLayeringTarget) {
|
||||
return;
|
||||
}
|
||||
// Prepare the IME screenshot for the last IME target when its task is applying app
|
||||
// transition. This is for the better IME transition to keep IME visibility when
|
||||
// transitioning to the next task.
|
||||
// If the IME target is the input target, before it changes, prepare the IME screenshot
|
||||
// for the last IME target when its task is applying app transition. This is for the
|
||||
// better IME transition to keep IME visibility when transitioning to the next task.
|
||||
if (mImeLayeringTarget != null && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
|
||||
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) {
|
||||
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)
|
||||
&& mImeLayeringTarget == mImeInputTarget) {
|
||||
attachAndShowImeScreenshotOnTarget();
|
||||
}
|
||||
|
||||
|
||||
@@ -1982,6 +1982,7 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// Test step 1: appWin1 is the current IME target and soft-keyboard is visible.
|
||||
mDisplayContent.computeImeTarget(true);
|
||||
assertEquals(appWin1, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
|
||||
mDisplayContent.setImeInputTarget(appWin1);
|
||||
spyOn(mDisplayContent.mInputMethodWindow);
|
||||
doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
|
||||
mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
|
||||
@@ -1998,7 +1999,6 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// be shown at this time.
|
||||
final Transaction t = mDisplayContent.getPendingTransaction();
|
||||
spyOn(t);
|
||||
mDisplayContent.setImeInputTarget(appWin2);
|
||||
mDisplayContent.computeImeTarget(true);
|
||||
assertEquals(appWin2, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
|
||||
assertTrue(mDisplayContent.shouldImeAttachedToApp());
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package com.android.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.server.wm.flicker.testapp.ActivityOptions
|
||||
import com.android.server.wm.traces.common.FlickerComponentName
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
@@ -47,4 +49,29 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
|
||||
}
|
||||
launcherStrategy.launch(appName, expectedPackage)
|
||||
}
|
||||
|
||||
fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
|
||||
val button = uiDevice.wait(Until.findObject(By.res(getPackage(),
|
||||
"start_dialog_themed_activity_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()
|
||||
wmHelper.waitForAppTransitionIdle()
|
||||
wmHelper.waitForFullScreenApp(
|
||||
ActivityOptions.DIALOG_THEMED_ACTIVITY_COMPONENT_NAME.toFlickerComponent())
|
||||
}
|
||||
fun dismissDialog(wmHelper: WindowManagerStateHelper) {
|
||||
val dialog = uiDevice.wait(
|
||||
Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT)
|
||||
|
||||
// Tapping outside of the dialog to dismiss
|
||||
if (dialog != null) {
|
||||
val dialogBounds = dialog.visibleBounds
|
||||
uiDevice.click(dialogBounds.left, dialogBounds.top - 300)
|
||||
wmHelper.waitForAppTransitionIdle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.app.Instrumentation
|
||||
import android.platform.test.annotations.Presubmit
|
||||
import android.view.Surface
|
||||
import android.view.WindowManagerPolicyConstants
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.server.wm.flicker.FlickerBuilderProvider
|
||||
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
|
||||
import com.android.server.wm.flicker.FlickerTestParameter
|
||||
import com.android.server.wm.flicker.FlickerTestParameterFactory
|
||||
import com.android.server.wm.flicker.dsl.FlickerBuilder
|
||||
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
|
||||
import com.android.server.wm.traces.common.FlickerComponentName
|
||||
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 snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
|
||||
* To run this test: `atest FlickerTests:LaunchAppShowImeAndDialogThemeAppTest`
|
||||
*/
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestParameter) {
|
||||
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
|
||||
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
|
||||
|
||||
@FlickerBuilderProvider
|
||||
fun buildFlicker(): FlickerBuilder {
|
||||
return FlickerBuilder(instrumentation).apply {
|
||||
setup {
|
||||
eachRun {
|
||||
testApp.launchViaIntent(wmHelper)
|
||||
wmHelper.waitImeShown()
|
||||
testApp.startDialogThemedActivity(wmHelper)
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
testApp.exit()
|
||||
}
|
||||
}
|
||||
transitions {
|
||||
testApp.dismissDialog(wmHelper)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that [FlickerComponentName.IME] layer becomes visible during the transition
|
||||
*/
|
||||
@Presubmit
|
||||
@Test
|
||||
fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible()
|
||||
|
||||
/**
|
||||
* Checks that [FlickerComponentName.IME] layer is visible at the end of the transition
|
||||
*/
|
||||
@Presubmit
|
||||
@Test
|
||||
fun imeLayerExistsEnd() {
|
||||
testSpec.assertLayersEnd {
|
||||
this.isVisible(FlickerComponentName.IME)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that [FlickerComponentName.IME_SNAPSHOT] layer is invisible always.
|
||||
*/
|
||||
@Presubmit
|
||||
@Test
|
||||
fun imeSnapshotNotVisible() {
|
||||
testSpec.assertLayers {
|
||||
this.isInvisible(FlickerComponentName.IME_SNAPSHOT)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Creates the test configurations.
|
||||
*
|
||||
* See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
|
||||
* repetitions, screen orientation and navigation modes.
|
||||
*/
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<FlickerTestParameter> {
|
||||
return FlickerTestParameterFactory.getInstance()
|
||||
.getConfigNonRotationTests(
|
||||
repetitions = 3,
|
||||
supportedRotations = listOf(Surface.ROTATION_0),
|
||||
supportedNavigationModes = listOf(
|
||||
WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
|
||||
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,5 +97,16 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".DialogThemedActivity"
|
||||
android:taskAffinity="com.android.server.wm.flicker.testapp.DialogThemedActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:theme="@style/DialogTheme"
|
||||
android:label="DialogThemedActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -31,4 +31,9 @@
|
||||
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" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -27,4 +27,14 @@
|
||||
<style name="CutoutNever">
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">never</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
<style name="DialogTheme" parent="@android:style/Theme.DeviceDefault">
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -56,4 +56,8 @@ public class ActivityOptions {
|
||||
public static final ComponentName LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME =
|
||||
new ComponentName(FLICKER_APP_PACKAGE,
|
||||
FLICKER_APP_PACKAGE + ".LaunchNewTaskActivity");
|
||||
public static final String DIALOG_THEMED_ACTIVITY = "DialogThemedActivity";
|
||||
public static final ComponentName DIALOG_THEMED_ACTIVITY_COMPONENT_NAME =
|
||||
new ComponentName(FLICKER_APP_PACKAGE,
|
||||
FLICKER_APP_PACKAGE + ".DialogThemedActivity");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.testapp;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class DialogThemedActivity extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_simple);
|
||||
getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
|
||||
TextView textView = new TextView(this);
|
||||
textView.setText("This is a test dialog");
|
||||
textView.setTextColor(Color.BLACK);
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setBackgroundColor(Color.GREEN);
|
||||
layout.addView(textView);
|
||||
|
||||
// Create a dialog with dialog-themed activity
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setView(layout)
|
||||
.setTitle("Dialog for test")
|
||||
.create();
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(MATCH_PARENT,
|
||||
MATCH_PARENT);
|
||||
attrs.flags = FLAG_DIM_BEHIND | FLAG_ALT_FOCUSABLE_IM;
|
||||
dialog.getWindow().getDecorView().setLayoutParams(attrs);
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
dialog.show();
|
||||
dialog.setOnDismissListener((d) -> finish());
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.wm.flicker.testapp;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class ImeActivityAutoFocus extends ImeActivity {
|
||||
@@ -26,5 +28,9 @@ public class ImeActivityAutoFocus extends ImeActivity {
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user