Merge "Move IME to a host display when target's display is reparented"

This commit is contained in:
Taran Singh
2020-01-30 22:25:16 +00:00
committed by Android (Google) Code Review
6 changed files with 126 additions and 31 deletions

View File

@@ -122,6 +122,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_ERROR;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -3416,6 +3417,57 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
&& mInputMethodTarget.mActivityRecord.matchParentBounds());
}
/**
* Get IME target that should host IME when this display that is reparented to another
* WindowState.
* IME is never displayed in a child display.
* Use {@link WindowState#getImeControlTarget()} when IME target window
* which originally called
* {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known.
*
* @return {@link WindowState} of host that controls IME.
* {@code null} when {@param dc} is not a virtual display.
* @see DisplayContent#reparent
*/
@Nullable
WindowState getImeControlTarget() {
WindowState imeTarget = mInputMethodTarget;
if (imeTarget != null) {
return imeTarget.getImeControlTarget();
}
return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow();
}
/**
* Finds the window which can host IME if IME target cannot host it.
* e.g. IME target cannot host IME when it's display has a parent display OR when display
* doesn't support IME/system decorations.
*
* @param target current IME target.
* @return {@link WindowState} that can host IME.
* @see DisplayContent#getImeControlTarget()
*/
WindowState getImeHostOrFallback(WindowState target) {
if (target != null && target.getDisplayContent().canShowIme()) {
return target;
}
// host is in non-default display that doesn't support system decor, default to
// default display's StatusBar to control IME.
// TODO: (b/148234093)find a better host OR control IME animation/visibility directly
// because it won't work when statusbar isn't available.
return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
}
boolean canShowIme() {
if (isUntrustedVirtualDisplay()) {
return false;
}
return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this)
|| mWmService.mForceDesktopModeOnExternalDisplays;
}
private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) {
if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) {
return;

View File

@@ -25,6 +25,13 @@ import android.view.WindowInsets.Type.InsetsType;
interface InsetsControlTarget {
void notifyInsetsControlChanged();
/**
* @return {@link WindowState} of this target, if any.
*/
default WindowState getWindow() {
return null;
}
/**
* Instructs the control target to show inset sources.
*

View File

@@ -222,6 +222,12 @@ class InsetsSourceProvider {
// to control the window for now.
return;
}
if (target != null && target.getWindow() != null) {
// ime control target could be a different window.
// Refer WindowState#getImeControlTarget().
target = target.getWindow().getImeControlTarget();
}
if (mWin == null) {
mControlTarget = target;
return;

View File

@@ -6991,8 +6991,15 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
boolean show;
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
ProtoLog.w(WM_ERROR,
"Attempted to get IME flag of a display that does not exist: %d",
displayId);
return false;
}
synchronized (mGlobalLock) {
show = shouldShowImeSystemWindowUncheckedLocked(displayId);
show = dc.canShowIme();
}
return show;
@@ -7405,15 +7412,13 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void showImePostLayout(IBinder imeTargetWindowToken) {
synchronized (mGlobalLock) {
final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
if (imeTarget == null) {
return;
}
final int displayId = imeTarget.getDisplayId();
if (!shouldShowImeSystemWindowUncheckedLocked(displayId)) {
return;
}
imeTarget = imeTarget.getImeControlTarget();
final int displayId = imeTarget.getDisplayId();
mRoot.getDisplayContent(displayId).getInsetsStateController().getImeSourceProvider()
.scheduleShowImePostLayout(imeTarget);
}
@@ -7423,12 +7428,16 @@ public class WindowManagerService extends IWindowManager.Stub
public void hideIme(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc != null && dc.mInputMethodTarget != null) {
if (dc != null) {
WindowState imeTarget = dc.getImeControlTarget();
if (imeTarget == null) {
return;
}
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(),
true /* fromIme */);
imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider()
.abortShowImePostLayout();
imeTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
}
}
}
@@ -7936,21 +7945,6 @@ public class WindowManagerService extends IWindowManager.Stub
return true;
}
private boolean shouldShowImeSystemWindowUncheckedLocked(final int displayId) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent == null) {
ProtoLog.w(WM_ERROR,
"Attempted to get IME flag of a display that does not exist: %d",
displayId);
return false;
}
if (displayContent.isUntrustedVirtualDisplay()) {
return false;
}
return mDisplayWindowSettings.shouldShowImeLocked(displayContent)
|| mForceDesktopModeOnExternalDisplays;
}
@Override
public void getWindowInsets(WindowManager.LayoutParams attrs,
int displayId, Rect outContentInsets, Rect outStableInsets,

View File

@@ -3517,6 +3517,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
@Override
public WindowState getWindow() {
return this;
}
@Override
public void showInsets(@InsetsType int types, boolean fromIme) {
try {
@@ -5334,6 +5339,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
/**
* Get IME target that should host IME when this window's display has a parent.
* Note: IME is never hosted by a display that has a parent.
* When window calling
* {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown,
* use {@link DisplayContent#getImeControlTarget()} instead.
*
* @return {@link WindowState} of host that controls the IME.
* When window is doesn't have a parent, it is returned as-is.
*/
WindowState getImeControlTarget() {
final DisplayContent dc = getDisplayContent();
final WindowState parentWindow = dc.getParentWindow();
// If target's display has a parent, IME is displayed in the parent display.
return dc.getImeHostOrFallback(parentWindow != null ? parentWindow : this);
}
@Override
void assignLayer(Transaction t, int layer) {
// See comment in assignRelativeLayerForImeTargetChild

View File

@@ -110,7 +110,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
mDisplayContent = createNewDisplay(true /* supportIme */);
// Set-up some common windows.
mCommonWindows = new HashSet<>();
@@ -349,16 +349,29 @@ class WindowTestsBase extends SystemServiceTestsBase {
return WindowTestUtils.createTaskInStack(mWm, stack, userId);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay() {
return createNewDisplay(mDisplayInfo);
return createNewDisplay(true /* supportIme */);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(boolean supportIme) {
return createNewDisplay(mDisplayInfo, supportIme);
}
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay(DisplayInfo info) {
return createNewDisplay(info, true /* supportIme */);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) {
final DisplayContent display =
new TestDisplayContent.Builder(mWm.mAtmService, info).build();
return display.mDisplayContent;
final DisplayContent dc = display.mDisplayContent;
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme);
return dc;
}
/**
@@ -372,7 +385,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
displayInfo.state = displayState;
return createNewDisplay(displayInfo);
return createNewDisplay(displayInfo, true /* supportIme */);
}
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
@@ -389,7 +402,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
displayInfo.copyFrom(mDisplayInfo);
displayInfo.type = Display.TYPE_VIRTUAL;
displayInfo.ownerUid = SYSTEM_UID;
return createNewDisplay(displayInfo);
return createNewDisplay(displayInfo, false /* supportIme */);
}
/** Sets the default minimum task size to 1 so that tests can use small task sizes */