Update IME layer when non-app window requests visible IME

For activity window, ImePlaceholder is either on top of
TaskDisplayArea or attaches on top of the ActivityRecord.
But for non-activity window, the ImePlaceholder needs to be
moved to another DisplayArea where the window resides.

Fix: 279847237
Test: atest InsetsStateControllerTest \
      #testUpdateAboveInsetsState_zOrderChanged
Change-Id: Id7b4b275913e96e2ccf12b36374a6263cff35490
This commit is contained in:
Riddle Hsu
2023-05-24 17:12:57 +08:00
parent d62eae979e
commit ad27d0cb45
2 changed files with 32 additions and 4 deletions

View File

@@ -90,6 +90,21 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
return control;
}
@Override
void setClientVisible(boolean clientVisible) {
final boolean wasClientVisible = isClientVisible();
super.setClientVisible(clientVisible);
// The layer of ImePlaceholder needs to be updated on a higher z-order for
// non-activity window (For activity window, IME is already on top of it).
if (!wasClientVisible && isClientVisible()) {
final InsetsControlTarget imeControlTarget = getControlTarget();
if (imeControlTarget != null && imeControlTarget.getWindow() != null
&& imeControlTarget.getWindow().mActivityRecord == null) {
mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */);
}
}
}
@Override
void setServerVisible(boolean serverVisible) {
mServerVisible = serverVisible;

View File

@@ -25,6 +25,7 @@ import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -38,6 +39,7 @@ 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.anyBoolean;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.spy;
@@ -420,10 +422,10 @@ public class InsetsStateControllerTest extends WindowTestsBase {
@Test
public void testUpdateAboveInsetsState_zOrderChanged() {
final WindowState ime = createTestWindow("ime");
final WindowState app = createTestWindow("app");
final WindowState statusBar = createTestWindow("statusBar");
final WindowState navBar = createTestWindow("navBar");
final WindowState ime = createNonAppWindow("ime");
final WindowState app = createNonAppWindow("app");
final WindowState statusBar = createNonAppWindow("statusBar");
final WindowState navBar = createNonAppWindow("navBar");
final InsetsSourceProvider imeSourceProvider =
getController().getOrCreateSourceProvider(ID_IME, ime());
@@ -431,7 +433,9 @@ public class InsetsStateControllerTest extends WindowTestsBase {
waitUntilHandlersIdle();
clearInvocations(mDisplayContent);
imeSourceProvider.updateControlForTarget(app, false /* force */);
imeSourceProvider.setClientVisible(true);
verify(mDisplayContent).assignWindowLayers(anyBoolean());
waitUntilHandlersIdle();
// The visibility change should trigger a traversal to notify the change.
verify(mDisplayContent).notifyInsetsChanged(any());
@@ -547,6 +551,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
control2.getInsetsHint().bottom);
}
/** Creates a window which is associated with ActivityRecord. */
private WindowState createTestWindow(String name) {
final WindowState win = createWindow(null, TYPE_APPLICATION, name);
win.setHasSurface(true);
@@ -554,6 +559,14 @@ public class InsetsStateControllerTest extends WindowTestsBase {
return win;
}
/** Creates a non-activity window. */
private WindowState createNonAppWindow(String name) {
final WindowState win = createWindow(null, LAST_APPLICATION_WINDOW + 1, name);
win.setHasSurface(true);
spyOn(win);
return win;
}
private InsetsStateController getController() {
return mDisplayContent.getInsetsStateController();
}