Loading services/core/java/com/android/server/wm/EmbeddedWindowController.java +52 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,18 @@ class EmbeddedWindowController { return embeddedWindow != null ? embeddedWindow.mHostWindowState : null; } boolean isOverlay(IBinder inputToken) { EmbeddedWindow embeddedWindow = mWindows.get(inputToken); return embeddedWindow != null ? embeddedWindow.getIsOverlay() : false; } void setIsOverlay(IBinder inputToken) { EmbeddedWindow embeddedWindow = mWindows.get(inputToken); if (embeddedWindow != null) { embeddedWindow.setIsOverlay(); } } void remove(IWindow client) { for (int i = mWindows.size() - 1; i >= 0; i--) { if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { Loading Loading @@ -138,6 +150,12 @@ class EmbeddedWindowController { public Session mSession; InputChannel mInputChannel; final int mWindowType; // Track whether the EmbeddedWindow is a system hosted overlay via // {@link OverlayHost}. In the case of client hosted overlays, the client // view hierarchy will take care of invoking requestEmbeddedWindowFocus // but for system hosted overlays we have to do this via tapOutsideDetection // and this variable is mostly used for tracking that. boolean mIsOverlay = false; /** * @param session calling session to check ownership of the window Loading Loading @@ -216,5 +234,39 @@ class EmbeddedWindowController { public int getPid() { return mOwnerPid; } void setIsOverlay() { mIsOverlay = true; } boolean getIsOverlay() { return mIsOverlay; } /** * System hosted overlays need the WM to invoke grantEmbeddedWindowFocus and * so we need to participate inside handlePointerDownOutsideFocus logic * however client hosted overlays will rely on the hosting view hierarchy * to grant and revoke focus, and so the server side logic is not needed. */ @Override public boolean receiveFocusFromTapOutside() { return mIsOverlay; } private void handleTap(boolean grantFocus) { if (mInputChannel != null) { mWmService.grantEmbeddedWindowFocus(mSession, mInputChannel.getToken(), grantFocus); } } @Override public void handleTapOutsideFocusOutsideSelf() { handleTap(false); } @Override public void handleTapOutsideFocusInsideSelf() { handleTap(true); } } } services/core/java/com/android/server/wm/InputTarget.java +11 −0 Original line number Diff line number Diff line Loading @@ -36,5 +36,16 @@ interface InputTarget { /* Owning pid of the target. */ int getPid(); /** * Indicates whether a target should receive focus from server side * tap outside focus detection. For example, this is false in the case of * EmbeddedWindows in a client view hierarchy, where the client will do internal * tap detection and invoke grantEmbeddedWindowFocus itself */ boolean receiveFocusFromTapOutside(); void handleTapOutsideFocusInsideSelf(); void handleTapOutsideFocusOutsideSelf(); } services/core/java/com/android/server/wm/OverlayHost.java +2 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ class OverlayHost { requireOverlaySurfaceControl(); mOverlays.add(p); mWmService.mEmbeddedWindowController.setIsOverlay(p.getInputToken()); SurfaceControl.Transaction t = mWmService.mTransactionFactory.get(); t.reparent(p.getSurfaceControl(), mSurfaceControl) .show(p.getSurfaceControl()); Loading services/core/java/com/android/server/wm/WindowManagerService.java +11 −16 Original line number Diff line number Diff line Loading @@ -738,6 +738,8 @@ public class WindowManagerService extends IWindowManager.Stub final WindowContextListenerController mWindowContextListenerController = new WindowContextListenerController(); private InputTarget mFocusedInputTarget; @VisibleForTesting final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = Loading Loading @@ -5011,6 +5013,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.v(TAG_WM, "Unknown focus tokens, dropping reportFocusChanged"); return; } mFocusedInputTarget = newTarget; mAccessibilityController.onFocusChanged(lastTarget, newTarget); ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastTarget, newTarget); Loading Loading @@ -8170,21 +8173,14 @@ public class WindowManagerService extends IWindowManager.Stub } private void onPointerDownOutsideFocusLocked(IBinder touchedToken) { WindowState touchedWindow = mInputToWindowMap.get(touchedToken); if (touchedWindow == null) { // if a user taps outside the currently focused window onto an embedded window, treat // it as if the host window was tapped. touchedWindow = mEmbeddedWindowController.getHostWindow(touchedToken); } if (touchedWindow == null || !touchedWindow.canReceiveKeys(true /* fromUserTouch */)) { InputTarget t = getInputTargetFromToken(touchedToken); if (t == null || !t.receiveFocusFromTapOutside()) { // If the window that received the input event cannot receive keys, don't move the // display it's on to the top since that window won't be able to get focus anyway. return; } if (mRecentsAnimationController != null && mRecentsAnimationController.getTargetAppMainWindow() == touchedWindow) { && mRecentsAnimationController.getTargetAppMainWindow() == t) { // If there is an active recents animation and touched window is the target, then ignore // the touch. The target already handles touches using its own input monitor and we // don't want to trigger any lifecycle changes from focusing another window. Loading @@ -8194,13 +8190,11 @@ public class WindowManagerService extends IWindowManager.Stub } ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", touchedWindow); final DisplayContent displayContent = touchedWindow.getDisplayContent(); if (!displayContent.isOnTop()) { displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); t); if (mFocusedInputTarget != t && mFocusedInputTarget != null) { mFocusedInputTarget.handleTapOutsideFocusOutsideSelf(); } handleTaskFocusChange(touchedWindow.getTask(), touchedWindow.mActivityRecord); t.handleTapOutsideFocusInsideSelf(); } @VisibleForTesting Loading Loading @@ -8777,4 +8771,5 @@ public class WindowManagerService extends IWindowManager.Stub mTaskTransitionSpec = null; } } services/core/java/com/android/server/wm/WindowState.java +20 −0 Original line number Diff line number Diff line Loading @@ -5985,4 +5985,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP boolean isTrustedOverlay() { return mInputWindowHandle.isTrustedOverlay(); } public boolean receiveFocusFromTapOutside() { return canReceiveKeys(true); } @Override public void handleTapOutsideFocusOutsideSelf() { // Nothing to do here since raising the other window will naturally take care of // us loosing focus } @Override public void handleTapOutsideFocusInsideSelf() { final DisplayContent displayContent = getDisplayContent(); if (!displayContent.isOnTop()) { displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); } mWmService.handleTaskFocusChange(getTask(), mActivityRecord); } } Loading
services/core/java/com/android/server/wm/EmbeddedWindowController.java +52 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,18 @@ class EmbeddedWindowController { return embeddedWindow != null ? embeddedWindow.mHostWindowState : null; } boolean isOverlay(IBinder inputToken) { EmbeddedWindow embeddedWindow = mWindows.get(inputToken); return embeddedWindow != null ? embeddedWindow.getIsOverlay() : false; } void setIsOverlay(IBinder inputToken) { EmbeddedWindow embeddedWindow = mWindows.get(inputToken); if (embeddedWindow != null) { embeddedWindow.setIsOverlay(); } } void remove(IWindow client) { for (int i = mWindows.size() - 1; i >= 0; i--) { if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { Loading Loading @@ -138,6 +150,12 @@ class EmbeddedWindowController { public Session mSession; InputChannel mInputChannel; final int mWindowType; // Track whether the EmbeddedWindow is a system hosted overlay via // {@link OverlayHost}. In the case of client hosted overlays, the client // view hierarchy will take care of invoking requestEmbeddedWindowFocus // but for system hosted overlays we have to do this via tapOutsideDetection // and this variable is mostly used for tracking that. boolean mIsOverlay = false; /** * @param session calling session to check ownership of the window Loading Loading @@ -216,5 +234,39 @@ class EmbeddedWindowController { public int getPid() { return mOwnerPid; } void setIsOverlay() { mIsOverlay = true; } boolean getIsOverlay() { return mIsOverlay; } /** * System hosted overlays need the WM to invoke grantEmbeddedWindowFocus and * so we need to participate inside handlePointerDownOutsideFocus logic * however client hosted overlays will rely on the hosting view hierarchy * to grant and revoke focus, and so the server side logic is not needed. */ @Override public boolean receiveFocusFromTapOutside() { return mIsOverlay; } private void handleTap(boolean grantFocus) { if (mInputChannel != null) { mWmService.grantEmbeddedWindowFocus(mSession, mInputChannel.getToken(), grantFocus); } } @Override public void handleTapOutsideFocusOutsideSelf() { handleTap(false); } @Override public void handleTapOutsideFocusInsideSelf() { handleTap(true); } } }
services/core/java/com/android/server/wm/InputTarget.java +11 −0 Original line number Diff line number Diff line Loading @@ -36,5 +36,16 @@ interface InputTarget { /* Owning pid of the target. */ int getPid(); /** * Indicates whether a target should receive focus from server side * tap outside focus detection. For example, this is false in the case of * EmbeddedWindows in a client view hierarchy, where the client will do internal * tap detection and invoke grantEmbeddedWindowFocus itself */ boolean receiveFocusFromTapOutside(); void handleTapOutsideFocusInsideSelf(); void handleTapOutsideFocusOutsideSelf(); }
services/core/java/com/android/server/wm/OverlayHost.java +2 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ class OverlayHost { requireOverlaySurfaceControl(); mOverlays.add(p); mWmService.mEmbeddedWindowController.setIsOverlay(p.getInputToken()); SurfaceControl.Transaction t = mWmService.mTransactionFactory.get(); t.reparent(p.getSurfaceControl(), mSurfaceControl) .show(p.getSurfaceControl()); Loading
services/core/java/com/android/server/wm/WindowManagerService.java +11 −16 Original line number Diff line number Diff line Loading @@ -738,6 +738,8 @@ public class WindowManagerService extends IWindowManager.Stub final WindowContextListenerController mWindowContextListenerController = new WindowContextListenerController(); private InputTarget mFocusedInputTarget; @VisibleForTesting final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = Loading Loading @@ -5011,6 +5013,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.v(TAG_WM, "Unknown focus tokens, dropping reportFocusChanged"); return; } mFocusedInputTarget = newTarget; mAccessibilityController.onFocusChanged(lastTarget, newTarget); ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastTarget, newTarget); Loading Loading @@ -8170,21 +8173,14 @@ public class WindowManagerService extends IWindowManager.Stub } private void onPointerDownOutsideFocusLocked(IBinder touchedToken) { WindowState touchedWindow = mInputToWindowMap.get(touchedToken); if (touchedWindow == null) { // if a user taps outside the currently focused window onto an embedded window, treat // it as if the host window was tapped. touchedWindow = mEmbeddedWindowController.getHostWindow(touchedToken); } if (touchedWindow == null || !touchedWindow.canReceiveKeys(true /* fromUserTouch */)) { InputTarget t = getInputTargetFromToken(touchedToken); if (t == null || !t.receiveFocusFromTapOutside()) { // If the window that received the input event cannot receive keys, don't move the // display it's on to the top since that window won't be able to get focus anyway. return; } if (mRecentsAnimationController != null && mRecentsAnimationController.getTargetAppMainWindow() == touchedWindow) { && mRecentsAnimationController.getTargetAppMainWindow() == t) { // If there is an active recents animation and touched window is the target, then ignore // the touch. The target already handles touches using its own input monitor and we // don't want to trigger any lifecycle changes from focusing another window. Loading @@ -8194,13 +8190,11 @@ public class WindowManagerService extends IWindowManager.Stub } ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", touchedWindow); final DisplayContent displayContent = touchedWindow.getDisplayContent(); if (!displayContent.isOnTop()) { displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); t); if (mFocusedInputTarget != t && mFocusedInputTarget != null) { mFocusedInputTarget.handleTapOutsideFocusOutsideSelf(); } handleTaskFocusChange(touchedWindow.getTask(), touchedWindow.mActivityRecord); t.handleTapOutsideFocusInsideSelf(); } @VisibleForTesting Loading Loading @@ -8777,4 +8771,5 @@ public class WindowManagerService extends IWindowManager.Stub mTaskTransitionSpec = null; } }
services/core/java/com/android/server/wm/WindowState.java +20 −0 Original line number Diff line number Diff line Loading @@ -5985,4 +5985,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP boolean isTrustedOverlay() { return mInputWindowHandle.isTrustedOverlay(); } public boolean receiveFocusFromTapOutside() { return canReceiveKeys(true); } @Override public void handleTapOutsideFocusOutsideSelf() { // Nothing to do here since raising the other window will naturally take care of // us loosing focus } @Override public void handleTapOutsideFocusInsideSelf() { final DisplayContent displayContent = getDisplayContent(); if (!displayContent.isOnTop()) { displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); } mWmService.handleTaskFocusChange(getTask(), mActivityRecord); } }