Fix WM input limitations on secondary displays (3/4)
One DisplayContent contains one InputMonitor now.
- Change setInputWindow of InputManagerService updated by displayId,
so Window Handles in InputDispather can be updated by each DisplayContent.
- Only exist one focus in current state, reset it if in removed DisplayContent,
will be updated by default display or focused display.
- Add displayId parameter for createInputConsumer and destroyInputConsumer,
so InputConsumer from PIP, RecentApp and Wallpaper can be supported in multi-display.
Bug: 111363643
Test: atest WindowManagerSmokeTest ActivityManagerMultiDisplayTests
Test: atest com.android.server.wm.DisplayContentTests
Test: atest libinput_tests inputflinger_tests
Change-Id: I999c355be1789af5759f00206475d004e10116e3
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 54cc07a..d53fd4a 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -159,8 +159,8 @@
Landroid/view/IRemoteAnimationRunner$Stub;-><init>()V
Landroid/view/IRemoteAnimationRunner;->onAnimationCancelled()V
Landroid/view/IRemoteAnimationRunner;->onAnimationStart([Landroid/view/RemoteAnimationTarget;Landroid/view/IRemoteAnimationFinishedCallback;)V
-Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lang/String;Landroid/view/InputChannel;)V
-Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;)Z
+Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lang/String;ILandroid/view/InputChannel;)V
+Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;I)Z
Landroid/view/IWindowManager;->endProlongedAnimations()V
Landroid/view/IWindowManager;->getStableInsets(ILandroid/graphics/Rect;)V
Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z)V
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0398b8f..15ca5ad 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -392,15 +392,16 @@
void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
/**
- * Create an input consumer by name.
+ * Create an input consumer by name and display id.
*/
- void createInputConsumer(IBinder token, String name, out InputChannel inputChannel);
+ void createInputConsumer(IBinder token, String name, int displayId,
+ out InputChannel inputChannel);
/**
- * Destroy an input consumer by name. This method will also dispose the input channels
- * associated with that InputConsumer.
+ * Destroy an input consumer by name and display id.
+ * This method will also dispose the input channels associated with that InputConsumer.
*/
- boolean destroyInputConsumer(String name);
+ boolean destroyInputConsumer(String name, int displayId);
/**
* Return the touch region for the current IME window, or an empty region if there is none.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index 0d25c91..0cde9da 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -146,8 +147,9 @@
if (mInputEventReceiver == null) {
final InputChannel inputChannel = new InputChannel();
try {
- mWindowManager.destroyInputConsumer(mName);
- mWindowManager.createInputConsumer(mToken, mName, inputChannel);
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create input consumer", e);
}
@@ -164,7 +166,8 @@
public void unregisterInputConsumer() {
if (mInputEventReceiver != null) {
try {
- mWindowManager.destroyInputConsumer(mName);
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
} catch (RemoteException e) {
Log.e(TAG, "Failed to destroy input consumer", e);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 9df9ba6..26bce92 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,25 +17,6 @@
package com.android.server.input;
import android.annotation.NonNull;
-import android.os.LocaleList;
-import android.os.ShellCallback;
-import android.util.Log;
-import android.view.Display;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.R;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
-import com.android.server.DisplayThread;
-import com.android.server.LocalServices;
-import com.android.server.Watchdog;
-import com.android.server.policy.WindowManagerPolicy;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.Manifest;
import android.app.IInputForwarder;
import android.app.Notification;
import android.app.NotificationManager;
@@ -50,8 +31,8 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
@@ -61,10 +42,10 @@
import android.hardware.display.DisplayViewport;
import android.hardware.input.IInputDevicesChangedListener;
import android.hardware.input.IInputManager;
+import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
-import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.TouchCalibration;
import android.os.Binder;
@@ -72,6 +53,7 @@
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
@@ -81,6 +63,7 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -97,6 +80,23 @@
import android.view.ViewConfiguration;
import android.widget.Toast;
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
+import com.android.server.Watchdog;
+import com.android.server.policy.WindowManagerPolicy;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import org.xmlpull.v1.XmlPullParser;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -113,9 +113,6 @@
import java.util.Locale;
import java.util.Objects;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
/*
* Wraps the C++ InputManager and provides its callbacks.
*/
@@ -212,7 +209,8 @@
int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
int policyFlags);
private static native void nativeToggleCapsLock(long ptr, int deviceId);
- private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
+ private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
+ int displayId);
private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
private static native void nativeSetFocusedApplication(long ptr,
@@ -1467,7 +1465,7 @@
}
public void setInputWindows(InputWindowHandle[] windowHandles,
- InputWindowHandle focusedWindowHandle) {
+ InputWindowHandle focusedWindowHandle, int displayId) {
final IWindow newFocusedWindow =
focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
if (mFocusedWindow != newFocusedWindow) {
@@ -1476,7 +1474,7 @@
setPointerCapture(false);
}
}
- nativeSetInputWindows(mPtr, windowHandles);
+ nativeSetInputWindows(mPtr, windowHandles, displayId);
}
public void setFocusedApplication(InputApplicationHandle application) {
diff --git a/services/core/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
index 720eaaa5..bb29bf8 100644
--- a/services/core/java/com/android/server/input/InputWindowHandle.java
+++ b/services/core/java/com/android/server/input/InputWindowHandle.java
@@ -17,8 +17,8 @@
package com.android.server.input;
import android.graphics.Region;
-import android.view.InputChannel;
import android.view.IWindow;
+import android.view.InputChannel;
/**
* Functions as a handle for a window that can receive input.
@@ -106,7 +106,7 @@
@Override
public String toString() {
- return new StringBuilder(name)
+ return new StringBuilder(name != null ? name : "")
.append(", layer=").append(layer)
.append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",")
.append(frameRight).append(",").append(frameBottom).append("]")
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ba46737..82c1808 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -814,9 +814,7 @@
// {@link DisplayContent} ready for use.
mDisplayReady = true;
- // TODO(b/112081256): Use independent InputMonitor.
- mInputMonitor = isDefaultDisplay ? new InputMonitor(service, mDisplayId)
- : mService.getDefaultDisplayContentLocked().mInputMonitor;
+ mInputMonitor = new InputMonitor(service, mDisplayId);
}
boolean isReady() {
@@ -2180,6 +2178,7 @@
mRemovingDisplay = false;
}
+ mInputMonitor.onRemoved();
mService.onDisplayRemoved(mDisplayId);
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 6a08f4d..585a4f5 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -20,9 +20,9 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.view.Display;
import android.view.InputChannel;
import android.view.WindowManager;
+
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index c4beb55..3309798 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -367,6 +367,13 @@
}
}
+ void onRemoved() {
+ // If DisplayContent removed, we need find a way to remove window handles of this display
+ // from InputDispatcher, so pass an empty InputWindowHandles to remove them.
+ mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle,
+ mDisplayId);
+ }
+
private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
InputConsumerImpl navInputConsumer;
InputConsumerImpl pipInputConsumer;
@@ -399,8 +406,7 @@
this.inDrag = inDrag;
wallpaperController = mService.mRoot.mWallpaperController;
- // TODO(b/112081256): Use independent InputMonitor for each display.
- mService.mRoot/*.getDisplayContent(mDisplayId)*/.forAllWindows(this,
+ mService.mRoot.getDisplayContent(mDisplayId).forAllWindows(this,
true /* traverseTopToBottom */);
if (mAddWallpaperInputConsumerHandle) {
// No visible wallpaper found, add the wallpaper input consumer at the end.
@@ -408,8 +414,8 @@
}
// Send windows to native code.
- // TODO: Update Input windows and focus by display?
- mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
+ mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle,
+ mDisplayId);
clearInputWindowHandlesLw();
@@ -429,7 +435,8 @@
final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
final int type = w.mAttrs.type;
- final boolean hasFocus = w == mInputFocus;
+ // TODO(b/111361570): multi-display focus, one focus window per display.
+ final boolean hasFocus = w.isFocused();
final boolean isVisible = w.isVisibleLw();
if (mAddRecentsAnimationInputConsumerHandle) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index da77edf..50fe7e3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6036,11 +6036,10 @@
}
@Override
- public void createInputConsumer(IBinder token, String name, InputChannel inputChannel) {
+ public void createInputConsumer(IBinder token, String name, int displayId,
+ InputChannel inputChannel) {
synchronized (mWindowMap) {
- // TODO(b/112049699): Fix this for multiple displays. There is only one inputChannel
- // here to accept the return value.
- DisplayContent display = mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+ DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
display.getInputMonitor().createInputConsumer(token, name, inputChannel,
Binder.getCallingPid(), Binder.getCallingUserHandle());
@@ -6049,11 +6048,9 @@
}
@Override
- public boolean destroyInputConsumer(String name) {
+ public boolean destroyInputConsumer(String name, int displayId) {
synchronized (mWindowMap) {
- // TODO(b/112049699): Fix this for multiple displays. For consistency with
- // createInputConsumer above.
- DisplayContent display = mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+ DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
return display.getInputMonitor().destroyInputConsumer(name);
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 52f2d67..16c0bf3 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -210,7 +210,7 @@
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
- void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
+ void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiVisibility(int32_t visibility);
@@ -736,7 +736,8 @@
}
}
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
+void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,
+ int32_t displayId) {
Vector<sp<InputWindowHandle> > windowHandles;
if (windowHandleObjArray) {
@@ -756,7 +757,7 @@
}
}
- mInputManager->getDispatcher()->setInputWindows(windowHandles);
+ mInputManager->getDispatcher()->setInputWindows(windowHandles, displayId);
// Do this after the dispatcher has updated the window handle state.
bool newPointerGesturesEnabled = true;
@@ -1446,10 +1447,10 @@
}
static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jobjectArray windowHandleObjArray) {
+ jlong ptr, jobjectArray windowHandleObjArray, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setInputWindows(env, windowHandleObjArray);
+ im->setInputWindows(env, windowHandleObjArray, displayId);
}
static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
@@ -1678,7 +1679,7 @@
(void*) nativeInjectInputEvent },
{ "nativeToggleCapsLock", "(JI)V",
(void*) nativeToggleCapsLock },
- { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V",
+ { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;I)V",
(void*) nativeSetInputWindows },
{ "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V",
(void*) nativeSetFocusedApplication },