From 4163d6288dcf76aa26e288e135a85fba27b8e034 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Tue, 22 May 2018 16:56:35 +0200 Subject: [PATCH] WM: Prevent secondary display focus while keyguard is up Fixes an issue where input intended for the keyguard could end up going to a different display. To prevent this, make sure that only the default display can get focused when the keyguard is showing. Change-Id: I6463c44aedca06930d2c9bda7c45ffd93141308c Fixes: 71786287 Test: atest DisplayContentTests --- .../android/server/policy/PhoneWindowManager.java | 6 +++++- .../server/policy/WindowManagerPolicy.java | 5 +++++ .../policy/keyguard/KeyguardStateMonitor.java | 2 ++ .../android/server/wm/RootWindowContainer.java | 8 ++++++++ .../android/server/wm/WindowManagerService.java | 13 +++++++++++++ .../android/server/wm/DisplayContentTests.java | 15 +++++++++++++++ .../server/wm/TestWindowManagerPolicy.java | 5 +++-- .../server/wm/WindowManagerServiceRule.java | 8 +++++++- 8 files changed, 58 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 16440c8189592..063fd619d1547 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -234,7 +234,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayCutout; -import android.view.DisplayInfo; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.IApplicationToken; @@ -2287,6 +2286,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onTrustedChanged() { mWindowManagerFuncs.notifyKeyguardTrustedChanged(); } + + @Override + public void onShowingChanged() { + mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged(); + } }); mScreenshotHelper = new ScreenshotHelper(mContext); } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 33eafb9e3e335..02dd6e61707c5 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -660,6 +660,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * abort animations that have no timeout, in case they got stuck. */ void triggerAnimationFailsafe(); + + /** + * The keyguard showing state has changed + */ + void onKeyguardShowingAndNotOccludedChanged(); } /** Window has been added to the screen. */ diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index e56caf849aac2..1cba1c7bed1b1 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -94,6 +94,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { public void onShowingStateChanged(boolean showing) { mIsShowing = showing; + mCallback.onShowingChanged(); try { mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId); } catch (RemoteException e) { @@ -132,6 +133,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { public interface StateCallback { void onTrustedChanged(); + void onShowingChanged(); } public void dump(String prefix, PrintWriter pw) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 50d0d0a5f1f9b..a709c55bbd30c 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -157,10 +157,18 @@ class RootWindowContainer extends WindowContainer { } WindowState computeFocusedWindow() { + // While the keyguard is showing, we must focus anything besides the main display. + // Otherwise we risk input not going to the keyguard when the user expects it to. + final boolean forceDefaultDisplay = mService.isKeyguardShowingAndNotOccluded(); + for (int i = mChildren.size() - 1; i >= 0; i--) { final DisplayContent dc = mChildren.get(i); final WindowState win = dc.findFocusedWindow(); if (win != null) { + if (forceDefaultDisplay && !dc.isDefaultDisplay) { + EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, ""); + continue; + } return win; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 224784bef257b..2c55ea3c2876c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2837,6 +2837,11 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.ANIMATION_FAILSAFE); } + @Override + public void onKeyguardShowingAndNotOccludedChanged() { + mH.sendEmptyMessage(H.RECOMPUTE_FOCUS); + } + /** * Starts deferring layout passes. Useful when doing multiple changes but to optimize * performance, only one layout pass should be done. This can be called multiple times, and @@ -4611,6 +4616,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int SET_HAS_OVERLAY_UI = 58; public static final int SET_RUNNING_REMOTE_ANIMATION = 59; public static final int ANIMATION_FAILSAFE = 60; + public static final int RECOMPUTE_FOCUS = 61; /** * Used to denote that an integer field in a message will not be used. @@ -5037,6 +5043,13 @@ public class WindowManagerService extends IWindowManager.Stub } } break; + case RECOMPUTE_FOCUS: { + synchronized (mWindowMap) { + updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, + true /* updateInputWindows */); + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 845095ae19b90..ac196f9c80dcf 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -329,6 +329,21 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(window1, sWm.mRoot.computeFocusedWindow()); } + @Test + public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception { + final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, + sWm.getDefaultDisplayContentLocked(), "keyguard"); + assertEquals(keyguard, sWm.mRoot.computeFocusedWindow()); + + // Add a window to a second display, and it should be focused + final DisplayContent dc = createNewDisplay(); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + assertEquals(win, sWm.mRoot.computeFocusedWindow()); + + mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true; + assertEquals(keyguard, sWm.mRoot.computeFocusedWindow()); + } + /** * This tests setting the maximum ui width on a display. */ diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 765b3d5957c4a..50f3fbefaf40c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -51,6 +51,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { private final Supplier mWmSupplier; int rotationToReport = 0; + boolean keyguardShowingAndNotOccluded = false; private Runnable mRunnableWhenAddingSplashScreen; @@ -338,7 +339,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public boolean isKeyguardLocked() { - return false; + return keyguardShowingAndNotOccluded; } @Override @@ -358,7 +359,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public boolean isKeyguardShowingAndNotOccluded() { - return false; + return keyguardShowingAndNotOccluded; } @Override diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java index 32bfda32de7fb..d91079e3bb1ba 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java @@ -59,6 +59,7 @@ import org.mockito.invocation.InvocationOnMock; public class WindowManagerServiceRule implements TestRule { private WindowManagerService mService; + private TestWindowManagerPolicy mPolicy; @Override public Statement apply(Statement base, Description description) { @@ -108,7 +109,7 @@ public class WindowManagerServiceRule implements TestRule { } mService = WindowManagerService.main(context, ims, true, false, - false, new TestWindowManagerPolicy( + false, mPolicy = new TestWindowManagerPolicy( WindowManagerServiceRule.this::getWindowManagerService)); mService.onInitReady(); @@ -132,6 +133,7 @@ public class WindowManagerServiceRule implements TestRule { waitUntilWindowManagerHandlersIdle(); removeServices(); mService = null; + mPolicy = null; } }; } @@ -140,6 +142,10 @@ public class WindowManagerServiceRule implements TestRule { return mService; } + public TestWindowManagerPolicy getWindowManagerPolicy() { + return mPolicy; + } + public void waitUntilWindowManagerHandlersIdle() { final WindowManagerService wm = getWindowManagerService(); if (wm != null) {