From c14513d81ef22cfbab93a9209f237534b3b5edc8 Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Wed, 14 Dec 2016 14:52:59 -0800 Subject: [PATCH] Add a Virtual 2D Display creator. Listens for changes to VrMode to create/destroy a Virtual Display for 2D apps. Test: Logs creation/destruction of vr display while toggling vr mode. Bug: 34280358 Change-Id: Idb52c4caa9aa0b6863cc6d2eaa55922ab81bf04a --- .../server/vr/CompatibilityDisplay.java | 119 ++++++++++++++++++ .../android/server/vr/VrManagerService.java | 8 ++ 2 files changed, 127 insertions(+) create mode 100644 services/core/java/com/android/server/vr/CompatibilityDisplay.java diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java new file mode 100644 index 0000000000000..15edaaf93af65 --- /dev/null +++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java @@ -0,0 +1,119 @@ + +package com.android.server.vr; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.DisplayManager; +import android.hardware.display.VirtualDisplay; +import android.os.Build; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.service.vr.IVrStateCallbacks; +import android.service.vr.IVrManager; +import android.util.Log; + +import com.android.server.vr.VrManagerService; + +/** + * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and + * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR. + */ +class CompatibilityDisplay { + private final static String TAG = "CompatDisplay"; + private final static boolean DEBUG = false; + + // TODO: Go over these values and figure out what is best + private final static int HEIGHT = 960; + private final static int WIDTH = 720; + private final static int DPI = 320; + + private final DisplayManager mDisplayManager; + private final IVrManager mVrManager; + + // TODO: Lock initially created when VrStateCallback was connected through Binder. This may not + // be necessary with the direct access to VrManager. + private final Object vdLock = new Object(); + + private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { + @Override + public void onVrStateChanged(boolean enabled) { + if (enabled != mIsVrModeEnabled) { + mIsVrModeEnabled = enabled; + if (enabled) { + // TODO: Consider not creating the display until ActivityManager needs one on + // which to display a 2D application. + startVirtualDisplay(); + } else { + stopVirtualDisplay(); + } + } + } + }; + + private VirtualDisplay mVirtualDisplay; + private boolean mIsVrModeEnabled; + + public CompatibilityDisplay(DisplayManager displayManager, IVrManager vrManager) { + mDisplayManager = displayManager; + mVrManager = vrManager; + } + + /** + * Initializes the compabilitiy display by listening to VR mode changes. + */ + public void init() { + startVrModeListener(); + } + + private void startVrModeListener() { + if (mVrManager != null) { + try { + mVrManager.registerListener(mVrStateCallbacks); + } catch (RemoteException e) { + Log.e(TAG, "Could not register VR State listener.", e); + } + } + } + + private void startVirtualDisplay() { + if (DEBUG) { + Log.d(TAG, "Starting VD, DM:" + mDisplayManager); + } + + if (mDisplayManager == null) { + Log.w(TAG, "Cannot create virtual display because mDisplayManager == null"); + return; + } + + synchronized (vdLock) { + if (mVirtualDisplay != null) { + Log.e(TAG, "Starting the virtual display when one already exists", new Exception()); + return; + } + + mVirtualDisplay = mDisplayManager.createVirtualDisplay("VR 2D Display", WIDTH, HEIGHT, + DPI, + null /* Surface */, 0 /* flags */); + } + + if (DEBUG) { + Log.d(TAG, "VD created: " + mVirtualDisplay); + } + } + + private void stopVirtualDisplay() { + if (DEBUG) { + Log.i(TAG, "Santos, stopping VD"); + } + + synchronized (vdLock) { + if (mVirtualDisplay != null) { + mVirtualDisplay.release(); + mVirtualDisplay = null; + } + } + } +} diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 84cf0c6e90427..57587b08c26bf 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -31,6 +31,7 @@ import android.content.pm.FeatureInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -51,6 +52,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; + import com.android.internal.R; import com.android.server.LocalServices; import com.android.server.SystemConfig; @@ -136,6 +138,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager(); /** Tracks the state of the screen and keyguard UI.*/ private int mSystemSleepFlags = FLAG_NONE; + private CompatibilityDisplay mCompatibilityDisplay; private static final int MSG_VR_STATE_CHANGE = 0; private static final int MSG_PENDING_VR_STATE_CHANGE = 1; @@ -493,6 +496,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC mComponentObserver.rebuildAll(); } + + DisplayManager dm = + (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE); + mCompatibilityDisplay = new CompatibilityDisplay(dm, mVrManager); + mCompatibilityDisplay.init(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mLock) { mVrModeAllowed = true;