Merge "Move the display targeted by a key event to top"
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4bc2416..ff93345 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -567,6 +567,10 @@
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
+ private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
+ private volatile boolean mMovingDisplayToTopKeyTriggered;
+ private volatile long mMovingDisplayToTopKeyTime;
+
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -606,7 +610,7 @@
private boolean mAodShowing;
private boolean mPerDisplayFocusEnabled = false;
- private int mTopFocusedDisplayId = INVALID_DISPLAY;
+ private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -634,6 +638,7 @@
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
private static final int MSG_RINGER_TOGGLE_CHORD = 27;
+ private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
private class PolicyHandler extends Handler {
@Override
@@ -729,6 +734,10 @@
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
+ case MSG_MOVE_DISPLAY_TO_TOP:
+ mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
+ mMovingDisplayToTopKeyTriggered = false;
+ break;
}
}
}
@@ -2570,12 +2579,25 @@
final int eventDisplayId = event.getDisplayId();
if (result == 0 && !mPerDisplayFocusEnabled
&& eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
- // Someone tries to send a key event to a display which doesn't have a focused window.
- // We drop the event here, or it will cause ANR.
- // TODO (b/121057974): The user may be confused about why the key doesn't work, so we
- // may need to deal with this problem.
- Slog.i(TAG, "Dropping this event targeting display #" + eventDisplayId
- + " because the focus is on display #" + mTopFocusedDisplayId);
+ // An event is targeting a non-focused display. Try to move the display to top so that
+ // it can become the focused display to interact with the user.
+ final long eventDownTime = event.getDownTime();
+ if (mMovingDisplayToTopKeyTime < eventDownTime) {
+ // We have not handled this event yet. Move the display to top, and then tell
+ // dispatcher to try again later.
+ mMovingDisplayToTopKeyTime = eventDownTime;
+ mMovingDisplayToTopKeyTriggered = true;
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
+ return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+ } else if (mMovingDisplayToTopKeyTriggered) {
+ // The message has not been handled yet. Tell dispatcher to try again later.
+ return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+ }
+ // The target display is still not the top focused display. Drop the event because the
+ // display may not contain any window which can receive keys.
+ Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
+ + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
return -1;
}
return result;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3da325c..c37254b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -634,6 +634,12 @@
* Notifies window manager that user is switched.
*/
void onUserSwitched();
+
+ /**
+ * Hint to window manager that the user is interacting with a display that should be treated
+ * as the top display.
+ */
+ void moveDisplayToTop(int displayId);
}
/**
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 937c9d9..58cf73a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -47,10 +47,9 @@
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
-import android.view.Surface;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import android.view.InsetsState;
import android.view.WindowManager;
import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -432,7 +431,7 @@
@Override
public void insetsModified(IWindow window, InsetsState state) {
- synchronized (mService.mWindowMap) {
+ synchronized (mService.mGlobalLock) {
final WindowState windowState = mService.windowForClientLocked(this, window,
false /* throwOnError */);
if (windowState != null) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index b219419..9057870 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -67,7 +67,7 @@
return;
}
WindowContainer parent = mDisplayContent.getParent();
- if (parent != null) {
+ if (parent != null && parent.getTopChild() != mDisplayContent) {
parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
true /* includingParents */);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 25e61f8..1905877 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -437,6 +437,7 @@
if (mChildren.peekLast() != child) {
mChildren.remove(child);
mChildren.add(child);
+ onChildPositionChanged();
}
if (includingParents && getParent() != null) {
getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -447,6 +448,7 @@
if (mChildren.peekFirst() != child) {
mChildren.remove(child);
mChildren.addFirst(child);
+ onChildPositionChanged();
}
if (includingParents && getParent() != null) {
getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -460,8 +462,8 @@
// doing this adjustment here and remove any adjustments in the callers.
mChildren.remove(child);
mChildren.add(position, child);
+ onChildPositionChanged();
}
- onChildPositionChanged();
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 90506e7..0c4f496 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -723,7 +723,7 @@
void updateSystemUiSettings() {
boolean changed;
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
|| PolicyControl.reloadFromSetting(mContext);
}
@@ -2629,12 +2629,23 @@
@Override
public void onUserSwitched() {
mSettingsObserver.updateSystemUiSettings();
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
}
}
+ @Override
+ public void moveDisplayToTop(int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null && mRoot.getTopChild() != displayContent) {
+ mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+ true /* includingParents */);
+ }
+ }
+ }
+
/**
* 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
@@ -6379,7 +6390,7 @@
}
void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
}
}