From b0608636a29bcec8ecb4391cd50f29f68b3e7e81 Mon Sep 17 00:00:00 2001
From: Santos Cordon
Date: Wed, 5 Apr 2017 10:31:15 -0700
Subject: [PATCH] Add uniqueId to Virtual Display and pass through to
inputflinger (1/2)
This CL adds:
1) Adds uniqueId (protected via system/sig permission) to virtual
displays.
2) Add support for N virtual display viewports into inputflinger.
3) Set the virtual display's viewports in inputflinger if it has the
uniqueId value set to non-null. (a) Moving the new viewport from java to
native inputflinger and (b) adding "uniqueId" value to viewports makes
up the great majority of this change.
4) From the inputflinger side, we also read in a new value from the
input device configuration files called 'touch.displayId'.
5) When touch.displayId and the virtual display's uniqueId match,
inputflinger links the two.
Test: Start VR and ensure that the virtual viewport shows up when running
'adb shell dump input". Run a VR app, and ensure that the virtual input
device is associated with the new virtual viewport.
Test: com.android.server.display.DisplayManagerServiceTest
Bug: 36051620
Change-Id: Ic2117eb8e19f7f3c59687160591f8bc6692c1f12
Merged-In: Ic2117eb8e19f7f3c59687160591f8bc6692c1f12
---
.../hardware/display/DisplayManager.java | 18 ++-
.../display/DisplayManagerGlobal.java | 5 +-
.../hardware/display/DisplayViewport.java | 48 +++++++
.../hardware/display/IDisplayManager.aidl | 2 +-
.../hardware/input/InputManagerInternal.java | 4 +-
core/jni/Android.mk | 1 +
...droid_hardware_display_DisplayViewport.cpp | 120 ++++++++++++++++++
...android_hardware_display_DisplayViewport.h | 34 +++++
.../media/projection/MediaProjection.java | 7 +-
.../java/com/android/server/Vr2dDisplay.java | 10 +-
.../server/am/ActivityStackSupervisor.java | 7 +-
.../server/display/DisplayDeviceInfo.java | 9 ++
.../server/display/DisplayManagerService.java | 84 ++++++++++--
.../server/display/VirtualDisplayAdapter.java | 39 +++++-
.../server/input/InputManagerService.java | 37 ++++--
...droid_server_input_InputManagerService.cpp | 82 ++++++++++--
services/core/jni/onload.cpp | 2 +
.../tests/servicestests/AndroidManifest.xml | 6 +-
.../display/DisplayManagerServiceTest.java | 118 +++++++++++++++++
19 files changed, 567 insertions(+), 66 deletions(-)
create mode 100644 core/jni/android_hardware_display_DisplayViewport.cpp
create mode 100644 core/jni/android_hardware_display_DisplayViewport.h
create mode 100644 services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 32671721f58b9..731a72d1ee8bd 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -251,6 +251,15 @@ public final class DisplayManager {
*/
public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
+ /**
+ * Virtual display flag: Specifies that the virtual display can be associated with a
+ * touchpad device that matches its uniqueId.
+ *
+ * @see #createVirtualDisplay
+ * @hide
+ */
+ public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -542,16 +551,17 @@ public final class DisplayManager {
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
- return createVirtualDisplay(null,
- name, width, height, densityDpi, surface, flags, callback, handler);
+ return createVirtualDisplay(null /* projection */, name, width, height, densityDpi, surface,
+ flags, callback, handler, null /* uniqueId */);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
- int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+ @Nullable String uniqueId) {
return mGlobal.createVirtualDisplay(mContext, projection,
- name, width, height, densityDpi, surface, flags, callback, handler);
+ name, width, height, densityDpi, surface, flags, callback, handler, uniqueId);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 341754c76edb4..876125e380141 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -383,7 +383,7 @@ public final class DisplayManagerGlobal {
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
- VirtualDisplay.Callback callback, Handler handler) {
+ VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name must be non-null and non-empty");
}
@@ -397,7 +397,8 @@ public final class DisplayManagerGlobal {
int displayId;
try {
displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
- context.getPackageName(), name, width, height, densityDpi, surface, flags);
+ context.getPackageName(), name, width, height, densityDpi, surface, flags,
+ uniqueId);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java
index c2d498b7fe684..bb41b45f21a57 100644
--- a/core/java/android/hardware/display/DisplayViewport.java
+++ b/core/java/android/hardware/display/DisplayViewport.java
@@ -17,6 +17,7 @@
package android.hardware.display;
import android.graphics.Rect;
+import android.text.TextUtils;
/**
* Describes how the pixels of physical display device reflects the content of
@@ -52,6 +53,9 @@ public final class DisplayViewport {
public int deviceWidth;
public int deviceHeight;
+ // The ID used to uniquely identify this display.
+ public String uniqueId;
+
public void copyFrom(DisplayViewport viewport) {
valid = viewport.valid;
displayId = viewport.displayId;
@@ -60,6 +64,49 @@ public final class DisplayViewport {
physicalFrame.set(viewport.physicalFrame);
deviceWidth = viewport.deviceWidth;
deviceHeight = viewport.deviceHeight;
+ uniqueId = viewport.uniqueId;
+ }
+
+ public DisplayViewport makeCopy() {
+ DisplayViewport dv = new DisplayViewport();
+ dv.copyFrom(this);
+ return dv;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof DisplayViewport)) {
+ return false;
+ }
+
+ DisplayViewport other = (DisplayViewport) o;
+ return valid == other.valid &&
+ displayId == other.displayId &&
+ orientation == other.orientation &&
+ logicalFrame.equals(other.logicalFrame) &&
+ physicalFrame.equals(other.physicalFrame) &&
+ deviceWidth == other.deviceWidth &&
+ deviceHeight == other.deviceHeight &&
+ TextUtils.equals(uniqueId, other.uniqueId);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result += prime * result + (valid ? 1 : 0);
+ result += prime * result + displayId;
+ result += prime * result + orientation;
+ result += prime * result + logicalFrame.hashCode();
+ result += prime * result + physicalFrame.hashCode();
+ result += prime * result + deviceWidth;
+ result += prime * result + deviceHeight;
+ result += prime * result + uniqueId.hashCode();
+ return result;
}
// For debugging purposes.
@@ -67,6 +114,7 @@ public final class DisplayViewport {
public String toString() {
return "DisplayViewport{valid=" + valid
+ ", displayId=" + displayId
+ + ", uniqueId='" + uniqueId + "'"
+ ", orientation=" + orientation
+ ", logicalFrame=" + logicalFrame
+ ", physicalFrame=" + physicalFrame
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index f696c8d154463..7ca4dc140eca2 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -66,7 +66,7 @@ interface IDisplayManager {
// MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in IVirtualDisplayCallback callback,
in IMediaProjection projectionToken, String packageName, String name,
- int width, int height, int densityDpi, in Surface surface, int flags);
+ int width, int height, int densityDpi, in Surface surface, int flags, String uniqueId);
// No permissions required, but must be same Uid as the creator.
void resizeVirtualDisplay(in IVirtualDisplayCallback token,
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 01a540484f1a9..4ea0f55218a94 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -22,6 +22,8 @@ import android.view.InputEvent;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import java.util.List;
+
/**
* Input manager local system service interface.
*
@@ -35,7 +37,7 @@ public abstract class InputManagerInternal {
* by the input system. The input system must copy this information to retain it.
*/
public abstract void setDisplayViewports(DisplayViewport defaultViewport,
- DisplayViewport externalTouchViewport);
+ DisplayViewport externalTouchViewport, List virtualTouchViewports);
/**
* Called by the power manager to tell the input manager whether it should start
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 77c72eb0e3d19..cab47582b8e8e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -162,6 +162,7 @@ LOCAL_SRC_FILES:= \
android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
android_hardware_camera2_legacy_PerfMeasurement.cpp \
android_hardware_camera2_DngCreator.cpp \
+ android_hardware_display_DisplayViewport.cpp \
android_hardware_HardwareBuffer.cpp \
android_hardware_Radio.cpp \
android_hardware_SensorManager.cpp \
diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp
new file mode 100644
index 0000000000000..1823a2cfeccbd
--- /dev/null
+++ b/core/jni/android_hardware_display_DisplayViewport.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DisplayViewport-JNI"
+
+#include "JNIHelp.h"
+#include "core_jni_helpers.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+ jclass clazz;
+
+ jfieldID displayId;
+ jfieldID orientation;
+ jfieldID logicalFrame;
+ jfieldID physicalFrame;
+ jfieldID deviceWidth;
+ jfieldID deviceHeight;
+ jfieldID uniqueId;
+} gDisplayViewportClassInfo;
+
+static struct {
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
+// ----------------------------------------------------------------------------
+
+status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject viewportObj,
+ DisplayViewport* viewport) {
+ viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId);
+ viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
+ viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth);
+ viewport->deviceHeight = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceHeight);
+
+ jstring uniqueId =
+ jstring(env->GetObjectField(viewportObj, gDisplayViewportClassInfo.uniqueId));
+ if (uniqueId != nullptr) {
+ viewport->uniqueId.setTo(ScopedUtfChars(env, uniqueId).c_str());
+ }
+
+ jobject logicalFrameObj =
+ env->GetObjectField(viewportObj, gDisplayViewportClassInfo.logicalFrame);
+ viewport->logicalLeft = env->GetIntField(logicalFrameObj, gRectClassInfo.left);
+ viewport->logicalTop = env->GetIntField(logicalFrameObj, gRectClassInfo.top);
+ viewport->logicalRight = env->GetIntField(logicalFrameObj, gRectClassInfo.right);
+ viewport->logicalBottom = env->GetIntField(logicalFrameObj, gRectClassInfo.bottom);
+
+ jobject physicalFrameObj =
+ env->GetObjectField(viewportObj, gDisplayViewportClassInfo.physicalFrame);
+ viewport->physicalLeft = env->GetIntField(physicalFrameObj, gRectClassInfo.left);
+ viewport->physicalTop = env->GetIntField(physicalFrameObj, gRectClassInfo.top);
+ viewport->physicalRight = env->GetIntField(physicalFrameObj, gRectClassInfo.right);
+ viewport->physicalBottom = env->GetIntField(physicalFrameObj, gRectClassInfo.bottom);
+
+ return OK;
+}
+
+// ----------------------------------------------------------------------------
+
+int register_android_hardware_display_DisplayViewport(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, "android/hardware/display/DisplayViewport");
+ gDisplayViewportClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+
+ gDisplayViewportClassInfo.displayId = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "displayId", "I");
+
+ gDisplayViewportClassInfo.orientation = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "orientation", "I");
+
+ gDisplayViewportClassInfo.deviceWidth = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "deviceWidth", "I");
+
+ gDisplayViewportClassInfo.deviceHeight = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "deviceHeight", "I");
+
+ gDisplayViewportClassInfo.logicalFrame = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "logicalFrame", "Landroid/graphics/Rect;");
+
+ gDisplayViewportClassInfo.physicalFrame = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "physicalFrame", "Landroid/graphics/Rect;");
+
+ gDisplayViewportClassInfo.uniqueId = GetFieldIDOrDie(env,
+ gDisplayViewportClassInfo.clazz, "uniqueId", "Ljava/lang/String;");
+
+ clazz = FindClassOrDie(env, "android/graphics/Rect");
+ gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
+ gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
+ gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
+ gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
+
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/android_hardware_display_DisplayViewport.h b/core/jni/android_hardware_display_DisplayViewport.h
new file mode 100644
index 0000000000000..5853177131631
--- /dev/null
+++ b/core/jni/android_hardware_display_DisplayViewport.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_HARDWARE_DISPLAY_DISPLAYVIEWPORT_H
+#define _ANDROID_HARDWARE_DISPLAY_DISPLAYVIEWPORT_H
+
+#include "jni.h"
+#include
+#include
+#include
+
+namespace android {
+
+/* Copies the contents of a DVM DisplayViewport object to a native DisplayViewport instance.
+ * Returns non-zero on error. */
+extern status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject eventObj,
+ DisplayViewport* viewport);
+
+} // namespace android
+
+#endif // _ANDROID_HARDWARE_DISPLAY_DISPLAYVIEWPORT_H
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index e757f093a4aea..f9c5b8d729c72 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -104,7 +104,8 @@ public final class MediaProjection {
int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
return dm.createVirtualDisplay(this, name, width, height, dpi, surface,
flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR |
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callback, handler);
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callback, handler,
+ null /* uniqueId */);
}
/**
@@ -134,8 +135,8 @@ public final class MediaProjection {
int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
- return dm.createVirtualDisplay(
- this, name, width, height, dpi, surface, flags, callback, handler);
+ return dm.createVirtualDisplay(this, name, width, height, dpi, surface, flags, callback,
+ handler, null /* uniqueId */);
}
/**
diff --git a/services/core/java/com/android/server/Vr2dDisplay.java b/services/core/java/com/android/server/Vr2dDisplay.java
index 1116e4e2c3fcd..f9bcb01b8c7bb 100644
--- a/services/core/java/com/android/server/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/Vr2dDisplay.java
@@ -40,6 +40,8 @@ class Vr2dDisplay {
private int mVirtualDisplayWidth;
private int mVirtualDisplayDpi;
private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
+ private final static String UNIQUE_DISPLAY_ID = "277f1a09-b88d-4d1e-8716-796f114d080b";
+ private final static String DISPLAY_NAME = "VR 2D Display";
private final static String DEBUG_ACTION_SET_MODE =
"com.android.server.vr.Vr2dDisplay.SET_MODE";
@@ -268,9 +270,11 @@ class Vr2dDisplay {
return;
}
- mVirtualDisplay = mDisplayManager.createVirtualDisplay("VR 2D Display",
- mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
- null /* Surface */, 0 /* flags */);
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
+ mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
+ DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
+ null /* surface */, flags, null /* callback */, null /* handler */,
+ UNIQUE_DISPLAY_ID);
if (mVirtualDisplay != null) {
mActivityManagerInternal.setVr2dDisplayId(
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d5b54ca8bf391..419f9c548b180 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4978,10 +4978,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
VirtualActivityDisplay(int width, int height, int density) {
DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, null,
- VIRTUAL_DISPLAY_BASE_NAME, width, height, density, null,
+ mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, null /* projection */,
+ VIRTUAL_DISPLAY_BASE_NAME, width, height, density, null /* surface */,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
- DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, null, null);
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, null /* callback */,
+ null /* handler */, null /* uniqueId */);
init(mVirtualDisplay.getDisplay());
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 4a52b3ce5d95c..ef6de4c1ee51f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -112,6 +112,13 @@ final class DisplayDeviceInfo {
*/
public static final int TOUCH_EXTERNAL = 2;
+ /**
+ * Touch attachment: Touch input is via an input device matching {@link VirtualDisplay}'s
+ * uniqueId.
+ * @hide
+ */
+ public static final int TOUCH_VIRTUAL = 3;
+
/**
* Diff result: The {@link #state} fields differ.
*/
@@ -391,6 +398,8 @@ final class DisplayDeviceInfo {
return "INTERNAL";
case TOUCH_EXTERNAL:
return "EXTERNAL";
+ case TOUCH_VIRTUAL:
+ return "VIRTUAL";
default:
return Integer.toString(touch);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 208295847e24d..8129f450a85bc 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -23,10 +23,12 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECUR
import static android.hardware.display.DisplayManager
.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import android.Manifest;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.SensorManager;
@@ -213,6 +215,7 @@ public final class DisplayManagerService extends SystemService {
// input from an external source. Used by the input system.
private final DisplayViewport mDefaultViewport = new DisplayViewport();
private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+ private final ArrayList mVirtualTouchViewports = new ArrayList<>();
// Persistent data store for all internal settings maintained by the display manager service.
private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
@@ -228,6 +231,7 @@ public final class DisplayManagerService extends SystemService {
// input system. May be used outside of the lock but only on the handler thread.
private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+ private final ArrayList mTempVirtualTouchViewports = new ArrayList<>();
// The default color mode for default displays. Overrides the usual
// Display.Display.COLOR_MODE_DEFAULT for displays with the
@@ -242,8 +246,16 @@ public final class DisplayManagerService extends SystemService {
// Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs.
private final SparseArray mDisplayAccessUIDs = new SparseArray<>();
+ private final Injector mInjector;
+
public DisplayManagerService(Context context) {
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ DisplayManagerService(Context context, Injector injector) {
super(context);
+ mInjector = injector;
mContext = context;
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
@@ -326,6 +338,11 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
+ @VisibleForTesting
+ Handler getDisplayHandler() {
+ return mHandler;
+ }
+
private void registerDisplayTransactionListenerInternal(
DisplayTransactionListener listener) {
// List is self-synchronized copy-on-write.
@@ -363,7 +380,8 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void performTraversalInTransactionFromWindowManagerInternal() {
+ @VisibleForTesting
+ void performTraversalInTransactionFromWindowManagerInternal() {
synchronized (mSyncRoot) {
if (!mPendingTraversal) {
return;
@@ -601,8 +619,8 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
- IMediaProjection projection, int callingUid, String packageName,
- String name, int width, int height, int densityDpi, Surface surface, int flags) {
+ IMediaProjection projection, int callingUid, String packageName, String name, int width,
+ int height, int densityDpi, Surface surface, int flags, String uniqueId) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
@@ -611,8 +629,8 @@ public final class DisplayManagerService extends SystemService {
}
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
- callback, projection, callingUid, packageName,
- name, width, height, densityDpi, surface, flags);
+ callback, projection, callingUid, packageName, name, width, height, densityDpi,
+ surface, flags, uniqueId);
if (device == null) {
return -1;
}
@@ -702,8 +720,8 @@ public final class DisplayManagerService extends SystemService {
}
private void registerVirtualDisplayAdapterLocked() {
- mVirtualDisplayAdapter = new VirtualDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
+ mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext, mHandler,
+ mDisplayAdapterListener);
registerDisplayAdapterLocked(mVirtualDisplayAdapter);
}
@@ -995,6 +1013,7 @@ public final class DisplayManagerService extends SystemService {
private void clearViewportsLocked() {
mDefaultViewport.valid = false;
mExternalTouchViewport.valid = false;
+ mVirtualTouchViewports.clear();
}
private void configureDisplayInTransactionLocked(DisplayDevice device) {
@@ -1033,6 +1052,28 @@ public final class DisplayManagerService extends SystemService {
&& info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
setViewportLocked(mExternalTouchViewport, display, device);
}
+
+ if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL && !TextUtils.isEmpty(info.uniqueId)) {
+ final DisplayViewport viewport = getVirtualTouchViewportLocked(info.uniqueId);
+ setViewportLocked(viewport, display, device);
+ }
+ }
+
+ /** Gets the virtual device viewport or creates it if not yet created. */
+ private DisplayViewport getVirtualTouchViewportLocked(@NonNull String uniqueId) {
+ DisplayViewport viewport;
+ final int count = mVirtualTouchViewports.size();
+ for (int i = 0; i < count; i++) {
+ viewport = mVirtualTouchViewports.get(i);
+ if (uniqueId.equals(viewport.uniqueId)) {
+ return viewport;
+ }
+ }
+
+ viewport = new DisplayViewport();
+ viewport.uniqueId = uniqueId;
+ mVirtualTouchViewports.add(viewport);
+ return viewport;
}
private static void setViewportLocked(DisplayViewport viewport,
@@ -1113,6 +1154,7 @@ public final class DisplayManagerService extends SystemService {
pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
+ pw.println(" mVirtualTouchViewports=" + mVirtualTouchViewports);
pw.println(" mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
@@ -1171,6 +1213,14 @@ public final class DisplayManagerService extends SystemService {
public static final class SyncRoot {
}
+ @VisibleForTesting
+ static class Injector {
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
+ Handler handler, DisplayAdapter.Listener displayAdapterListener) {
+ return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener);
+ }
+ }
+
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -1199,9 +1249,15 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) {
mTempDefaultViewport.copyFrom(mDefaultViewport);
mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
+ if (!mTempVirtualTouchViewports.equals(mVirtualTouchViewports)) {
+ mTempVirtualTouchViewports.clear();
+ for (DisplayViewport d : mVirtualTouchViewports) {
+ mTempVirtualTouchViewports.add(d.makeCopy());
+ }
+ }
}
- mInputManagerInternal.setDisplayViewports(
- mTempDefaultViewport, mTempExternalTouchViewport);
+ mInputManagerInternal.setDisplayViewports(mTempDefaultViewport,
+ mTempExternalTouchViewport, mTempVirtualTouchViewports);
break;
}
}
@@ -1264,7 +1320,8 @@ public final class DisplayManagerService extends SystemService {
}
}
- private final class BinderService extends IDisplayManager.Stub {
+ @VisibleForTesting
+ final class BinderService extends IDisplayManager.Stub {
/**
* Returns information about the specified logical display.
*
@@ -1458,7 +1515,8 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public int createVirtualDisplay(IVirtualDisplayCallback callback,
IMediaProjection projection, String packageName, String name,
- int width, int height, int densityDpi, Surface surface, int flags) {
+ int width, int height, int densityDpi, Surface surface, int flags,
+ String uniqueId) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -1520,8 +1578,8 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
- return createVirtualDisplayInternal(callback, projection, callingUid,
- packageName, name, width, height, densityDpi, surface, flags);
+ return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
+ name, width, height, densityDpi, surface, flags, uniqueId);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 514993380564a..9d3021af1ac24 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -22,6 +22,7 @@ import static android.hardware.display.DisplayManager
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
@@ -39,6 +40,8 @@ import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
import java.util.Iterator;
@@ -48,7 +51,8 @@ import java.util.Iterator;
* Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
*
*/
-final class VirtualDisplayAdapter extends DisplayAdapter {
+@VisibleForTesting
+public class VirtualDisplayAdapter extends DisplayAdapter {
static final String TAG = "VirtualDisplayAdapter";
static final boolean DEBUG = false;
@@ -57,27 +61,42 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
private final ArrayMap mVirtualDisplayDevices =
new ArrayMap();
- private Handler mHandler;
+ private final Handler mHandler;
+ private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
// Called with SyncRoot lock held.
public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
+ this(syncRoot, context, handler, listener,
+ (String name, boolean secure) -> SurfaceControl.createDisplay(name, secure));
+ }
+
+ @VisibleForTesting
+ VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
+ Context context, Handler handler, Listener listener,
+ SurfaceControlDisplayFactory surfaceControlDisplayFactory) {
super(syncRoot, context, handler, listener, TAG);
mHandler = handler;
+ mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
}
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
- IMediaProjection projection, int ownerUid, String ownerPackageName,
- String name, int width, int height, int densityDpi, Surface surface, int flags) {
+ IMediaProjection projection, int ownerUid, String ownerPackageName, String name,
+ int width, int height, int densityDpi, Surface surface, int flags, String uniqueId) {
boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
IBinder appToken = callback.asBinder();
- IBinder displayToken = SurfaceControl.createDisplay(name, secure);
+ IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure);
final String baseUniqueId =
UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
+ if (uniqueId == null) {
+ uniqueId = baseUniqueId + uniqueIndex;
+ } else {
+ uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
+ }
VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags,
- new Callback(callback, mHandler), baseUniqueId + uniqueIndex, uniqueIndex);
+ new Callback(callback, mHandler), uniqueId, uniqueIndex);
mVirtualDisplayDevices.put(appToken, device);
@@ -341,7 +360,8 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
}
mInfo.type = Display.TYPE_VIRTUAL;
- mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+ mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
+ DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
mInfo.ownerUid = mOwnerUid;
mInfo.ownerPackageName = mOwnerPackageName;
@@ -407,4 +427,9 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
}
}
}
+
+ @VisibleForTesting
+ public interface SurfaceControlDisplayFactory {
+ public IBinder createDisplay(String name, boolean secure);
+ }
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index aafc9a8f50d7a..907b5c1c43304 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -190,11 +190,13 @@ public class InputManagerService extends IInputManager.Stub
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);
- private static native void nativeSetDisplayViewport(long ptr, boolean external,
+ private static native void nativeSetVirtualDisplayViewports(long ptr,
+ DisplayViewport[] viewports);
+ private static native void nativeSetDisplayViewport(long ptr, int viewportType,
int displayId, int rotation,
int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
- int deviceWidth, int deviceHeight);
+ int deviceWidth, int deviceHeight, String uniqueId);
private static native int nativeGetScanCodeState(long ptr,
int deviceId, int sourceMask, int scanCode);
@@ -289,6 +291,11 @@ public class InputManagerService extends IInputManager.Stub
/** Switch code: Camera lens cover. When set the lens is covered. */
public static final int SW_CAMERA_LENS_COVER = 0x09;
+ // Viewport constants defined in InputReader.h.
+ public static final int VIEWPORT_DEFAULT = 1;
+ public static final int VIEWPORT_EXTERNAL = 2;
+ public static final int VIEWPORT_VIRTUAL = 3;
+
public static final int SW_LID_BIT = 1 << SW_LID;
public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
@@ -406,26 +413,30 @@ public class InputManagerService extends IInputManager.Stub
}
private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
- DisplayViewport externalTouchViewport) {
+ DisplayViewport externalTouchViewport,
+ List virtualTouchViewports) {
if (defaultViewport.valid) {
- setDisplayViewport(false, defaultViewport);
+ setDisplayViewport(VIEWPORT_DEFAULT, defaultViewport);
}
if (externalTouchViewport.valid) {
- setDisplayViewport(true, externalTouchViewport);
+ setDisplayViewport(VIEWPORT_EXTERNAL, externalTouchViewport);
} else if (defaultViewport.valid) {
- setDisplayViewport(true, defaultViewport);
+ setDisplayViewport(VIEWPORT_EXTERNAL, defaultViewport);
}
+
+ nativeSetVirtualDisplayViewports(mPtr,
+ virtualTouchViewports.toArray(new DisplayViewport[0]));
}
- private void setDisplayViewport(boolean external, DisplayViewport viewport) {
- nativeSetDisplayViewport(mPtr, external,
+ private void setDisplayViewport(int viewportType, DisplayViewport viewport) {
+ nativeSetDisplayViewport(mPtr, viewportType,
viewport.displayId, viewport.orientation,
viewport.logicalFrame.left, viewport.logicalFrame.top,
viewport.logicalFrame.right, viewport.logicalFrame.bottom,
viewport.physicalFrame.left, viewport.physicalFrame.top,
viewport.physicalFrame.right, viewport.physicalFrame.bottom,
- viewport.deviceWidth, viewport.deviceHeight);
+ viewport.deviceWidth, viewport.deviceHeight, viewport.uniqueId);
}
/**
@@ -2296,9 +2307,11 @@ public class InputManagerService extends IInputManager.Stub
private final class LocalService extends InputManagerInternal {
@Override
- public void setDisplayViewports(
- DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
- setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
+ public void setDisplayViewports(DisplayViewport defaultViewport,
+ DisplayViewport externalTouchViewport,
+ List virtualTouchViewports) {
+ setDisplayViewportsInternal(defaultViewport, externalTouchViewport,
+ virtualTouchViewports);
}
@Override
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8baa96bf9bae6..6f24e7e6197ff 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -57,6 +57,7 @@
#include "com_android_server_power_PowerManagerService.h"
#include "com_android_server_input_InputApplicationHandle.h"
#include "com_android_server_input_InputWindowHandle.h"
+#include "android_hardware_display_DisplayViewport.h"
#define INDENT " "
@@ -190,7 +191,8 @@ public:
void dump(String8& dump);
- void setDisplayViewport(bool external, const DisplayViewport& viewport);
+ void setVirtualDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray);
+ void setDisplayViewport(int32_t viewportType, const DisplayViewport& viewport);
status_t registerInputChannel(JNIEnv* env, const sp& inputChannel,
const sp& inputWindowHandle, bool monitor);
@@ -264,6 +266,7 @@ private:
// Display size information.
DisplayViewport internalViewport;
DisplayViewport externalViewport;
+ Vector virtualViewports;
// System UI visibility.
int32_t systemUiVisibility;
@@ -365,17 +368,53 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c
return false;
}
-void NativeInputManager::setDisplayViewport(bool external, const DisplayViewport& viewport) {
+void NativeInputManager::setVirtualDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray) {
+ Vector viewports;
+
+ if (viewportObjArray) {
+ jsize length = env->GetArrayLength(viewportObjArray);
+ for (jsize i = 0; i < length; i++) {
+ jobject viewportObj = env->GetObjectArrayElement(viewportObjArray, i);
+ if (! viewportObj) {
+ break; // found null element indicating end of used portion of the array
+ }
+
+ DisplayViewport viewport;
+ android_hardware_display_DisplayViewport_toNative(env, viewportObj, &viewport);
+ ALOGI("Viewport [%d] to add: %s", (int) length, viewport.uniqueId.c_str());
+ viewports.push(viewport);
+
+ env->DeleteLocalRef(viewportObj);
+ }
+ }
+
+ {
+ AutoMutex _l(mLock);
+ mLocked.virtualViewports = viewports;
+ }
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+}
+
+void NativeInputManager::setDisplayViewport(int32_t type, const DisplayViewport& viewport) {
bool changed = false;
{
AutoMutex _l(mLock);
- DisplayViewport& v = external ? mLocked.externalViewport : mLocked.internalViewport;
- if (v != viewport) {
- changed = true;
- v = viewport;
+ ViewportType viewportType = static_cast(type);
+ DisplayViewport* v = NULL;
+ if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
+ v = &mLocked.externalViewport;
+ } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
+ v = &mLocked.internalViewport;
+ }
- if (!external) {
+ if (v != NULL && *v != viewport) {
+ changed = true;
+ *v = viewport;
+
+ if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
sp controller = mLocked.pointerController.promote();
if (controller != NULL) {
controller->setDisplayViewport(
@@ -468,8 +507,11 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->pointerCapture = mLocked.pointerCapture;
- outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
- outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
+ outConfig->setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL,
+ mLocked.internalViewport);
+ outConfig->setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL,
+ mLocked.externalViewport);
+ outConfig->setVirtualDisplayViewports(mLocked.virtualViewports);
} // release lock
}
@@ -1153,11 +1195,17 @@ static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
}
}
-static void nativeSetDisplayViewport(JNIEnv* /* env */, jclass /* clazz */, jlong ptr,
- jboolean external, jint displayId, jint orientation,
+static void nativeSetVirtualDisplayViewports(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jobjectArray viewportObjArray) {
+ NativeInputManager* im = reinterpret_cast(ptr);
+ im->setVirtualDisplayViewports(env, viewportObjArray);
+}
+
+static void nativeSetDisplayViewport(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jint viewportType, jint displayId, jint orientation,
jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom,
- jint deviceWidth, jint deviceHeight) {
+ jint deviceWidth, jint deviceHeight, jstring uniqueId) {
NativeInputManager* im = reinterpret_cast(ptr);
DisplayViewport v;
@@ -1173,7 +1221,11 @@ static void nativeSetDisplayViewport(JNIEnv* /* env */, jclass /* clazz */, jlon
v.physicalBottom = physicalBottom;
v.deviceWidth = deviceWidth;
v.deviceHeight = deviceHeight;
- im->setDisplayViewport(external, v);
+ if (uniqueId != nullptr) {
+ v.uniqueId.setTo(ScopedUtfChars(env, uniqueId).c_str());
+ }
+
+ im->setDisplayViewport(viewportType, v);
}
static jint nativeGetScanCodeState(JNIEnv* /* env */, jclass /* clazz */,
@@ -1514,7 +1566,9 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*) nativeInit },
{ "nativeStart", "(J)V",
(void*) nativeStart },
- { "nativeSetDisplayViewport", "(JZIIIIIIIIIIII)V",
+ { "nativeSetVirtualDisplayViewports", "(J[Landroid/hardware/display/DisplayViewport;)V",
+ (void*) nativeSetVirtualDisplayViewports },
+ { "nativeSetDisplayViewport", "(JIIIIIIIIIIIIILjava/lang/String;)V",
(void*) nativeSetDisplayViewport },
{ "nativeGetScanCodeState", "(JIII)I",
(void*) nativeGetScanCodeState },
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index f22b330b5b9de..e96bda910c6cf 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -47,6 +47,7 @@ int register_android_server_Watchdog(JNIEnv* env);
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
+int register_android_hardware_display_DisplayViewport(JNIEnv* env);
};
using namespace android;
@@ -89,6 +90,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
register_android_server_GraphicsStatsService(env);
+ register_android_hardware_display_DisplayViewport(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index fa72416edd16d..686dad4a8340b 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -191,7 +191,7 @@
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.servicestests"
+ android:label="Frameworks Services Tests" />
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
new file mode 100644
index 0000000000000..c399a5de46dd5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayViewport;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.input.InputManagerInternal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.SurfaceControl;
+import android.view.WindowManagerInternal;
+
+import com.android.server.LocalServices;
+import com.android.server.display.DisplayManagerService.SyncRoot;
+import com.android.server.display.VirtualDisplayAdapter.SurfaceControlDisplayFactory;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+public class DisplayManagerServiceTest extends AndroidTestCase {
+ private Handler mHandler;
+ private DisplayManagerService mDisplayManager;
+ @Mock InputManagerInternal mMockInputManagerInternal;
+ @Mock IVirtualDisplayCallback.Stub mMockAppToken;
+ @Mock WindowManagerInternal mMockWindowManagerInternal;
+ @Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
+ @Mock IBinder mMockDisplayToken;
+
+ @Override
+ protected void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mDisplayManager = new DisplayManagerService(mContext,
+ new DisplayManagerService.Injector() {
+ @Override
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
+ Handler handler, DisplayAdapter.Listener displayAdapterListener) {
+ return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
+ (String name, boolean secure) -> mMockDisplayToken);
+ }
+ });
+ mHandler = mDisplayManager.getDisplayHandler();
+
+ LocalServices.removeServiceForTest(InputManagerInternal.class);
+ LocalServices.addService(InputManagerInternal.class, mMockInputManagerInternal);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
+
+ mDisplayManager.systemReady(false /* safeMode */, false /* onlyCore */);
+ mDisplayManager.windowManagerAndInputReady();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testCreateVirtualDisplay_sentToInputManager() throws Exception {
+ // This is effectively the DisplayManager service published to ServiceManager.
+ DisplayManagerService.BinderService bs = mDisplayManager.new BinderService();
+
+ String uniqueId = "uniqueId --- Test";
+ String uniqueIdPrefix = "virtual:" + mContext.getPackageName() + ":";
+ int width = 600;
+ int height = 800;
+ int dpi = 320;
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
+
+ when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ int displayId = bs.createVirtualDisplay(mMockAppToken /* callback */,
+ null /* projection */, "com.android.frameworks.servicestests",
+ "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
+ uniqueId);
+
+ mDisplayManager.performTraversalInTransactionFromWindowManagerInternal();
+
+ // flush the handler
+ mHandler.runWithScissors(() -> {}, 0 /* now */);
+
+ ArgumentCaptor> virtualViewportCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mMockInputManagerInternal).setDisplayViewports(
+ any(), any(), virtualViewportCaptor.capture());
+
+ assertEquals(1, virtualViewportCaptor.getValue().size());
+ DisplayViewport dv = virtualViewportCaptor.getValue().get(0);
+ assertEquals(height, dv.deviceHeight);
+ assertEquals(width, dv.deviceWidth);
+ assertEquals(uniqueIdPrefix + uniqueId, dv.uniqueId);
+ assertEquals(displayId, dv.displayId);
+ }
+}