Fix IME snapshot applied on non-IME input target window
In case when the activity shows IME, transitioning from non-IME input targeted dialog activity will see a weird IME snapshot sliding down animation during the dialog dismissing. Also added a flicker test to verify this behavior. Fix: 210868010 Test: manual as below steps: 1) Launch keep note app 2) Tap on any url link to popup "open with" dialog 3) Tap anywhere else on the screen to dismiss the dialog 4) Expect no IME sliding down animation Test: atest LaunchAppShowImeAndDialogThemeAppTest Test: atest DisplayContentTests#testAttachAndShowImeScreenshotOnTarget Change-Id: Ibccaea46547e57b3439c5e787f97a261fbb10125
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