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);
+ }
+}