Merge "Fix wrong ime parent in embedded activity" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4c10cba683
@@ -4505,24 +4505,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SurfaceControl computeImeParent() {
|
SurfaceControl computeImeParent() {
|
||||||
if (mImeLayeringTarget != null) {
|
if (!canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) {
|
||||||
// Ensure changing the IME parent when the layering target that may use IME has
|
return null;
|
||||||
// became to the input target for preventing IME flickers.
|
|
||||||
// Note that:
|
|
||||||
// 1) For the imeLayeringTarget that may not use IME but requires IME on top
|
|
||||||
// of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow
|
|
||||||
// it to re-parent the IME on top the display to keep the legacy behavior.
|
|
||||||
// 2) Even though the starting window won't use IME, the associated activity
|
|
||||||
// behind the starting window may request the input. If so, then we should still hold
|
|
||||||
// the IME parent change until the activity started the input.
|
|
||||||
boolean imeLayeringTargetMayUseIme =
|
|
||||||
LayoutParams.mayUseInputMethod(mImeLayeringTarget.mAttrs.flags)
|
|
||||||
|| mImeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;
|
|
||||||
if (imeLayeringTargetMayUseIme && (mImeInputTarget == null
|
|
||||||
|| mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord())) {
|
|
||||||
// Do not change parent if the window hasn't requested IME.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Attach it to app if the target is part of an app and such app is covering the entire
|
// Attach it to app if the target is part of an app and such app is covering the entire
|
||||||
// screen. If it's not covering the entire screen the IME might extend beyond the apps
|
// screen. If it's not covering the entire screen the IME might extend beyond the apps
|
||||||
@@ -4535,6 +4519,76 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
|
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget,
|
||||||
|
@Nullable InputTarget imeInputTarget) {
|
||||||
|
if (imeLayeringTarget == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Ensure changing the IME parent when the layering target that may use IME has
|
||||||
|
// became to the input target for preventing IME flickers.
|
||||||
|
// Note that:
|
||||||
|
// 1) For the imeLayeringTarget that may not use IME but requires IME on top
|
||||||
|
// of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow
|
||||||
|
// it to re-parent the IME on top the display to keep the legacy behavior.
|
||||||
|
// 2) Even though the starting window won't use IME, the associated activity
|
||||||
|
// behind the starting window may request the input. If so, then we should still hold
|
||||||
|
// the IME parent change until the activity started the input.
|
||||||
|
boolean imeLayeringTargetMayUseIme =
|
||||||
|
LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags)
|
||||||
|
|| imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;
|
||||||
|
|
||||||
|
if (imeLayeringTargetMayUseIme && (imeInputTarget == null
|
||||||
|
|| imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord())) {
|
||||||
|
// Do not change parent if the window hasn't requested IME.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from {@link #computeImeParent()} to check the given IME targets if the IME surface
|
||||||
|
* parent should be updated in ActivityEmbeddings.
|
||||||
|
*
|
||||||
|
* As the IME layering target is calculated according to the window hierarchy by
|
||||||
|
* {@link #computeImeTarget}, the layering target and input target may be different when the
|
||||||
|
* window hasn't started input connection, WindowManagerService hasn't yet received the
|
||||||
|
* input target which reported from InputMethodManagerService. To make the IME surface will be
|
||||||
|
* shown on the best fit IME layering target, we basically won't update IME parent until both
|
||||||
|
* IME input and layering target updated for better IME transition.
|
||||||
|
*
|
||||||
|
* However, in activity embedding, tapping a window won't update it to the top window so the
|
||||||
|
* calculated IME layering target may higher than input target. Update IME parent for this case.
|
||||||
|
*
|
||||||
|
* @return {@code true} means the layer of IME layering target is higher than the input target
|
||||||
|
* and {@link #computeImeParent()} should keep progressing to update the IME
|
||||||
|
* surface parent on the display in case the IME surface left behind.
|
||||||
|
*/
|
||||||
|
private static boolean shouldComputeImeParentForEmbeddedActivity(
|
||||||
|
@Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) {
|
||||||
|
if (imeInputTarget == null || imeLayeringTarget == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final WindowState inputTargetWindow = imeInputTarget.getWindowState();
|
||||||
|
if (inputTargetWindow == null || !imeLayeringTarget.isAttached()
|
||||||
|
|| !inputTargetWindow.isAttached()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord();
|
||||||
|
final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord();
|
||||||
|
if (inputTargetRecord == null || layeringTargetRecord == null
|
||||||
|
|| inputTargetRecord == layeringTargetRecord
|
||||||
|
|| inputTargetRecord.getTask() != layeringTargetRecord.getTask()
|
||||||
|
|| !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) {
|
||||||
|
// Check whether the input target and layering target are embedded in the same Task.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return imeLayeringTarget.compareTo(inputTargetWindow) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
void setLayoutNeeded() {
|
void setLayoutNeeded() {
|
||||||
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
|
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
|
||||||
mLayoutNeeded = true;
|
mLayoutNeeded = true;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
|||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
|
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||||
|
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||||
@@ -603,4 +604,34 @@ public class TaskFragmentTest extends WindowTestsBase {
|
|||||||
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, tf1.getOrientation(SCREEN_ORIENTATION_UNSET));
|
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, tf1.getOrientation(SCREEN_ORIENTATION_UNSET));
|
||||||
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, task.getOrientation(SCREEN_ORIENTATION_UNSET));
|
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, task.getOrientation(SCREEN_ORIENTATION_UNSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateImeParentForActivityEmbedding() {
|
||||||
|
// Setup two activities in ActivityEmbedding.
|
||||||
|
final Task task = createTask(mDisplayContent);
|
||||||
|
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
||||||
|
.setParentTask(task)
|
||||||
|
.createActivityCount(1)
|
||||||
|
.setOrganizer(mOrganizer)
|
||||||
|
.setFragmentToken(new Binder())
|
||||||
|
.build();
|
||||||
|
final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
|
||||||
|
.setParentTask(task)
|
||||||
|
.createActivityCount(1)
|
||||||
|
.setOrganizer(mOrganizer)
|
||||||
|
.setFragmentToken(new Binder())
|
||||||
|
.build();
|
||||||
|
final ActivityRecord activity0 = tf0.getTopMostActivity();
|
||||||
|
final ActivityRecord activity1 = tf1.getTopMostActivity();
|
||||||
|
final WindowState win0 = createWindow(null, TYPE_BASE_APPLICATION, activity0, "win0");
|
||||||
|
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity1, "win1");
|
||||||
|
doReturn(false).when(mDisplayContent).shouldImeAttachedToApp();
|
||||||
|
|
||||||
|
mDisplayContent.setImeInputTarget(win0);
|
||||||
|
mDisplayContent.setImeLayeringTarget(win1);
|
||||||
|
|
||||||
|
// The ImeParent should be the display.
|
||||||
|
assertEquals(mDisplayContent.getImeContainer().getParent().getSurfaceControl(),
|
||||||
|
mDisplayContent.computeImeParent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user