blob: a16dbb7266135aafafc596f07f9eaaa5e09c469b [file] [log] [blame]
Santos Cordonc14513d2016-12-14 14:52:59 -08001package com.android.server.vr;
2
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -08003import static android.view.Display.INVALID_DISPLAY;
4
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -08005import android.app.ActivityManagerInternal;
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -07006import android.app.Vr2dDisplayProperties;
Santos Cordon2f22da72017-02-27 17:24:44 -08007import android.content.BroadcastReceiver;
Santos Cordonc14513d2016-12-14 14:52:59 -08008import android.content.Context;
9import android.content.Intent;
Santos Cordon2f22da72017-02-27 17:24:44 -080010import android.content.IntentFilter;
Daniel Nicoara5a2ca722017-04-05 17:38:16 -040011import android.graphics.PixelFormat;
Santos Cordonc14513d2016-12-14 14:52:59 -080012import android.hardware.display.DisplayManager;
13import android.hardware.display.VirtualDisplay;
Santos Cordon975c00d2017-03-21 17:05:36 -070014import android.media.ImageReader;
Santos Cordonc14513d2016-12-14 14:52:59 -080015import android.os.Handler;
Santos Cordonc14513d2016-12-14 14:52:59 -080016import android.os.RemoteException;
Santos Cordon975c00d2017-03-21 17:05:36 -070017import android.service.vr.IPersistentVrStateCallbacks;
Santos Cordonc14513d2016-12-14 14:52:59 -080018import android.service.vr.IVrManager;
19import android.util.Log;
Santos Cordon2f22da72017-02-27 17:24:44 -080020import android.view.Surface;
Santos Cordonc14513d2016-12-14 14:52:59 -080021
Wale Ogunwale6767eae2018-05-03 15:52:51 -070022import com.android.server.LocalServices;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070023import com.android.server.wm.ActivityTaskManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +010024import com.android.server.wm.WindowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -080025
26/**
27 * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
28 * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR.
29 */
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070030class Vr2dDisplay {
31 private final static String TAG = "Vr2dDisplay";
Santos Cordonc14513d2016-12-14 14:52:59 -080032 private final static boolean DEBUG = false;
33
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070034 private int mVirtualDisplayHeight;
35 private int mVirtualDisplayWidth;
36 private int mVirtualDisplayDpi;
Santos Cordon975c00d2017-03-21 17:05:36 -070037 private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
Santos Cordonb0608632017-04-05 10:31:15 -070038 private final static String UNIQUE_DISPLAY_ID = "277f1a09-b88d-4d1e-8716-796f114d080b";
39 private final static String DISPLAY_NAME = "VR 2D Display";
Santos Cordonc14513d2016-12-14 14:52:59 -080040
Santos Cordon2f22da72017-02-27 17:24:44 -080041 private final static String DEBUG_ACTION_SET_MODE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070042 "com.android.server.vr.Vr2dDisplay.SET_MODE";
Santos Cordon2f22da72017-02-27 17:24:44 -080043 private final static String DEBUG_EXTRA_MODE_ON =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070044 "com.android.server.vr.Vr2dDisplay.EXTRA_MODE_ON";
Santos Cordon2f22da72017-02-27 17:24:44 -080045 private final static String DEBUG_ACTION_SET_SURFACE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070046 "com.android.server.vr.Vr2dDisplay.SET_SURFACE";
Santos Cordon2f22da72017-02-27 17:24:44 -080047 private final static String DEBUG_EXTRA_SURFACE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070048 "com.android.server.vr.Vr2dDisplay.EXTRA_SURFACE";
Santos Cordon2f22da72017-02-27 17:24:44 -080049
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070050 /**
51 * The default width of the VR virtual display
52 */
Santos Cordonc22c5632017-06-21 16:03:49 -070053 public static final int DEFAULT_VIRTUAL_DISPLAY_WIDTH = 1400;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070054
55 /**
56 * The default height of the VR virtual display
57 */
Karthik Ravi Shankar6d1575f2017-07-06 10:23:57 -070058 public static final int DEFAULT_VIRTUAL_DISPLAY_HEIGHT = 1800;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070059
60 /**
61 * The default height of the VR virtual dpi.
62 */
Santos Cordonc22c5632017-06-21 16:03:49 -070063 public static final int DEFAULT_VIRTUAL_DISPLAY_DPI = 320;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070064
65 /**
66 * The minimum height, width and dpi of VR virtual display.
67 */
68 public static final int MIN_VR_DISPLAY_WIDTH = 1;
69 public static final int MIN_VR_DISPLAY_HEIGHT = 1;
70 public static final int MIN_VR_DISPLAY_DPI = 1;
71
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -080072 private final ActivityManagerInternal mActivityManagerInternal;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070073 private final WindowManagerInternal mWindowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -080074 private final DisplayManager mDisplayManager;
75 private final IVrManager mVrManager;
Santos Cordon975c00d2017-03-21 17:05:36 -070076 private final Object mVdLock = new Object();
77 private final Handler mHandler = new Handler();
Santos Cordonc14513d2016-12-14 14:52:59 -080078
Santos Cordon975c00d2017-03-21 17:05:36 -070079 /**
80 * Callback implementation to receive changes to VrMode.
81 **/
82 private final IPersistentVrStateCallbacks mVrStateCallbacks =
83 new IPersistentVrStateCallbacks.Stub() {
Santos Cordonc14513d2016-12-14 14:52:59 -080084 @Override
Santos Cordon975c00d2017-03-21 17:05:36 -070085 public void onPersistentVrStateChanged(boolean enabled) {
Santos Cordonc22c5632017-06-21 16:03:49 -070086 if (enabled != mIsPersistentVrModeEnabled) {
87 mIsPersistentVrModeEnabled = enabled;
Santos Cordon2f22da72017-02-27 17:24:44 -080088 updateVirtualDisplay();
Santos Cordonc14513d2016-12-14 14:52:59 -080089 }
90 }
91 };
92
93 private VirtualDisplay mVirtualDisplay;
Santos Cordon2f22da72017-02-27 17:24:44 -080094 private Surface mSurface;
Santos Cordon975c00d2017-03-21 17:05:36 -070095 private ImageReader mImageReader;
96 private Runnable mStopVDRunnable;
Santos Cordonc22c5632017-06-21 16:03:49 -070097 private boolean mIsVrModeOverrideEnabled; // debug override to set vr mode.
98 private boolean mIsVirtualDisplayAllowed = true; // Virtual-display feature toggle
99 private boolean mIsPersistentVrModeEnabled; // indicates we are in vr persistent mode.
100 private boolean mBootsToVr = false; // The device boots into VR (standalone VR device)
Santos Cordonc14513d2016-12-14 14:52:59 -0800101
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -0700102 public Vr2dDisplay(DisplayManager displayManager,
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700103 ActivityManagerInternal activityManagerInternal,
104 WindowManagerInternal windowManagerInternal, IVrManager vrManager) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800105 mDisplayManager = displayManager;
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800106 mActivityManagerInternal = activityManagerInternal;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700107 mWindowManagerInternal = windowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -0800108 mVrManager = vrManager;
Santos Cordonc22c5632017-06-21 16:03:49 -0700109 mVirtualDisplayWidth = DEFAULT_VIRTUAL_DISPLAY_WIDTH;
110 mVirtualDisplayHeight = DEFAULT_VIRTUAL_DISPLAY_HEIGHT;
111 mVirtualDisplayDpi = DEFAULT_VIRTUAL_DISPLAY_DPI;
Santos Cordonc14513d2016-12-14 14:52:59 -0800112 }
113
114 /**
115 * Initializes the compabilitiy display by listening to VR mode changes.
116 */
Santos Cordonc22c5632017-06-21 16:03:49 -0700117 public void init(Context context, boolean bootsToVr) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800118 startVrModeListener();
Santos Cordon2f22da72017-02-27 17:24:44 -0800119 startDebugOnlyBroadcastReceiver(context);
Santos Cordonc22c5632017-06-21 16:03:49 -0700120 mBootsToVr = bootsToVr;
121 if (mBootsToVr) {
122 // If we are booting into VR, we need to start the virtual display immediately. This
123 // ensures that the virtual display is up by the time Setup Wizard is started.
124 updateVirtualDisplay();
125 }
Santos Cordon2f22da72017-02-27 17:24:44 -0800126 }
127
Santos Cordon975c00d2017-03-21 17:05:36 -0700128 /**
129 * Creates and Destroys the virtual display depending on the current state of VrMode.
130 */
Santos Cordon2f22da72017-02-27 17:24:44 -0800131 private void updateVirtualDisplay() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700132 if (DEBUG) {
Santos Cordonc22c5632017-06-21 16:03:49 -0700133 Log.i(TAG, "isVrMode: " + mIsPersistentVrModeEnabled + ", override: "
134 + mIsVrModeOverrideEnabled + ", isAllowed: " + mIsVirtualDisplayAllowed
135 + ", bootsToVr: " + mBootsToVr);
Santos Cordon975c00d2017-03-21 17:05:36 -0700136 }
137
Santos Cordon627a68f2017-06-12 17:57:17 -0700138 if (shouldRunVirtualDisplay()) {
Santos Cordonc22c5632017-06-21 16:03:49 -0700139 Log.i(TAG, "Attempting to start virtual display");
Santos Cordon2f22da72017-02-27 17:24:44 -0800140 // TODO: Consider not creating the display until ActivityManager needs one on
141 // which to display a 2D application.
Santos Cordon5dc60192017-05-09 11:36:53 -0700142 startVirtualDisplay();
Santos Cordon2f22da72017-02-27 17:24:44 -0800143 } else {
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800144 // Stop virtual display to test exit condition
145 stopVirtualDisplay();
Santos Cordon2f22da72017-02-27 17:24:44 -0800146 }
147 }
148
Santos Cordon975c00d2017-03-21 17:05:36 -0700149 /**
150 * Creates a DEBUG-only BroadcastReceiver through which a test app can simulate VrMode and
151 * set a custom Surface for the virtual display. This allows testing of the virtual display
152 * without going into full 3D.
153 *
154 * @param context The context.
155 */
Santos Cordon2f22da72017-02-27 17:24:44 -0800156 private void startDebugOnlyBroadcastReceiver(Context context) {
Santos Cordon5dc60192017-05-09 11:36:53 -0700157 if (DEBUG) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800158 IntentFilter intentFilter = new IntentFilter(DEBUG_ACTION_SET_MODE);
159 intentFilter.addAction(DEBUG_ACTION_SET_SURFACE);
160
161 context.registerReceiver(new BroadcastReceiver() {
162 @Override
163 public void onReceive(Context context, Intent intent) {
164 final String action = intent.getAction();
165 if (DEBUG_ACTION_SET_MODE.equals(action)) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700166 mIsVrModeOverrideEnabled =
Santos Cordon2f22da72017-02-27 17:24:44 -0800167 intent.getBooleanExtra(DEBUG_EXTRA_MODE_ON, false);
168 updateVirtualDisplay();
169 } else if (DEBUG_ACTION_SET_SURFACE.equals(action)) {
170 if (mVirtualDisplay != null) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700171 if (intent.hasExtra(DEBUG_EXTRA_SURFACE)) {
172 setSurfaceLocked(intent.getParcelableExtra(DEBUG_EXTRA_SURFACE));
Santos Cordon2f22da72017-02-27 17:24:44 -0800173 }
174 } else {
175 Log.w(TAG, "Cannot set the surface because the VD is null.");
176 }
177 }
178 }
179 }, intentFilter);
180 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800181 }
182
Santos Cordon975c00d2017-03-21 17:05:36 -0700183 /**
184 * Starts listening to VrMode changes.
185 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800186 private void startVrModeListener() {
187 if (mVrManager != null) {
188 try {
Santos Cordon975c00d2017-03-21 17:05:36 -0700189 mVrManager.registerPersistentVrStateListener(mVrStateCallbacks);
Santos Cordonc14513d2016-12-14 14:52:59 -0800190 } catch (RemoteException e) {
191 Log.e(TAG, "Could not register VR State listener.", e);
192 }
193 }
194 }
195
Santos Cordon975c00d2017-03-21 17:05:36 -0700196 /**
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -0700197 * Sets the resolution and DPI of the Vr2d virtual display used to display
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700198 * 2D applications in VR mode.
199 *
200 * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
201 *
Santos Cordon627a68f2017-06-12 17:57:17 -0700202 * @param displayProperties Properties of the virtual display for 2D applications
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700203 * in VR mode.
204 */
Santos Cordon627a68f2017-06-12 17:57:17 -0700205 public void setVirtualDisplayProperties(Vr2dDisplayProperties displayProperties) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700206 synchronized(mVdLock) {
207 if (DEBUG) {
Santos Cordon627a68f2017-06-12 17:57:17 -0700208 Log.i(TAG, "VD setVirtualDisplayProperties: " +
209 displayProperties.toString());
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700210 }
211
Santos Cordon627a68f2017-06-12 17:57:17 -0700212 int width = displayProperties.getWidth();
213 int height = displayProperties.getHeight();
214 int dpi = displayProperties.getDpi();
215 boolean resized = false;
216
217 if (width < MIN_VR_DISPLAY_WIDTH || height < MIN_VR_DISPLAY_HEIGHT ||
218 dpi < MIN_VR_DISPLAY_DPI) {
219 Log.i(TAG, "Ignoring Width/Height/Dpi values of " + width + "," + height + ","
220 + dpi);
221 } else {
222 Log.i(TAG, "Setting width/height/dpi to " + width + "," + height + "," + dpi);
223 mVirtualDisplayWidth = width;
224 mVirtualDisplayHeight = height;
225 mVirtualDisplayDpi = dpi;
226 resized = true;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700227 }
228
rongliu55492662018-03-21 14:34:58 -0700229 if ((displayProperties.getAddedFlags() &
230 Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
Santos Cordon627a68f2017-06-12 17:57:17 -0700231 == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
232 mIsVirtualDisplayAllowed = true;
233 } else if ((displayProperties.getRemovedFlags() &
234 Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
235 == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
236 mIsVirtualDisplayAllowed = false;
237 }
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700238
Santos Cordon627a68f2017-06-12 17:57:17 -0700239 if (mVirtualDisplay != null && resized && mIsVirtualDisplayAllowed) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700240 mVirtualDisplay.resize(mVirtualDisplayWidth, mVirtualDisplayHeight,
241 mVirtualDisplayDpi);
242 ImageReader oldImageReader = mImageReader;
243 mImageReader = null;
244 startImageReader();
245 oldImageReader.close();
246 }
Santos Cordon627a68f2017-06-12 17:57:17 -0700247
248 // Start/Stop the virtual display in case the updates indicated that we should.
249 updateVirtualDisplay();
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700250 }
251 }
252
253 /**
Santos Cordon975c00d2017-03-21 17:05:36 -0700254 * Returns the virtual display ID if one currently exists, otherwise returns
255 * {@link INVALID_DISPLAY_ID}.
256 *
257 * @return The virtual display ID.
258 */
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800259 public int getVirtualDisplayId() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700260 synchronized(mVdLock) {
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800261 if (mVirtualDisplay != null) {
262 int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
263 if (DEBUG) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700264 Log.i(TAG, "VD id: " + virtualDisplayId);
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800265 }
266 return virtualDisplayId;
267 }
268 }
269 return INVALID_DISPLAY;
270 }
271
Santos Cordon975c00d2017-03-21 17:05:36 -0700272 /**
273 * Starts the virtual display if one does not already exist.
274 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800275 private void startVirtualDisplay() {
276 if (DEBUG) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800277 Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
Santos Cordonc14513d2016-12-14 14:52:59 -0800278 }
279
280 if (mDisplayManager == null) {
281 Log.w(TAG, "Cannot create virtual display because mDisplayManager == null");
282 return;
283 }
284
Santos Cordon975c00d2017-03-21 17:05:36 -0700285 synchronized (mVdLock) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800286 if (mVirtualDisplay != null) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800287 Log.i(TAG, "VD already exists, ignoring request");
Santos Cordonc14513d2016-12-14 14:52:59 -0800288 return;
289 }
290
Santos Cordonb0608632017-04-05 10:31:15 -0700291 int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
Alex Sakhartchouk879d24f2017-06-20 22:01:19 -0400292 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
Karthik Ravi Shankar4c657382017-09-26 13:40:58 -0700293 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
294 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
rongliu1e90fc32017-10-04 17:30:30 -0700295 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
Santos Cordonb6992f22018-01-30 14:51:20 -0800296 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
297
Santos Cordonb0608632017-04-05 10:31:15 -0700298 mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
299 DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
300 null /* surface */, flags, null /* callback */, null /* handler */,
301 UNIQUE_DISPLAY_ID);
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800302
303 if (mVirtualDisplay != null) {
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700304 updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
Santos Cordon728d81f2017-04-12 15:20:33 -0700305 // Now create the ImageReader to supply a Surface to the new virtual display.
306 startImageReader();
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800307 } else {
308 Log.w(TAG, "Virtual display id is null after createVirtualDisplay");
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700309 updateDisplayId(INVALID_DISPLAY);
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800310 return;
311 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800312 }
313
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700314 Log.i(TAG, "VD created: " + mVirtualDisplay);
Santos Cordonc14513d2016-12-14 14:52:59 -0800315 }
316
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700317 private void updateDisplayId(int displayId) {
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700318 LocalServices.getService(ActivityTaskManagerInternal.class).setVr2dDisplayId(displayId);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700319 mWindowManagerInternal.setVr2dDisplayId(displayId);
320 }
321
Santos Cordon975c00d2017-03-21 17:05:36 -0700322 /**
323 * Stops the virtual display with a {@link #STOP_VIRTUAL_DISPLAY_DELAY_MILLIS} timeout.
324 * The timeout prevents the virtual display from bouncing in cases where VrMode goes in and out
325 * of being enabled. This can happen sometimes with our 2D test app.
326 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800327 private void stopVirtualDisplay() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700328 if (mStopVDRunnable == null) {
329 mStopVDRunnable = new Runnable() {
330 @Override
331 public void run() {
Santos Cordon627a68f2017-06-12 17:57:17 -0700332 if (shouldRunVirtualDisplay()) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700333 Log.i(TAG, "Virtual Display destruction stopped: VrMode is back on.");
334 } else {
335 Log.i(TAG, "Stopping Virtual Display");
336 synchronized (mVdLock) {
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700337 updateDisplayId(INVALID_DISPLAY);
Santos Cordon975c00d2017-03-21 17:05:36 -0700338 setSurfaceLocked(null); // clean up and release the surface first.
339 if (mVirtualDisplay != null) {
340 mVirtualDisplay.release();
341 mVirtualDisplay = null;
342 }
Santos Cordon728d81f2017-04-12 15:20:33 -0700343 stopImageReader();
Santos Cordon975c00d2017-03-21 17:05:36 -0700344 }
345 }
346 }
347 };
Santos Cordonc14513d2016-12-14 14:52:59 -0800348 }
349
Santos Cordon975c00d2017-03-21 17:05:36 -0700350 mHandler.removeCallbacks(mStopVDRunnable);
351 mHandler.postDelayed(mStopVDRunnable, STOP_VIRTUAL_DISPLAY_DELAY_MILLIS);
352 }
353
354 /**
355 * Set the surface to use with the virtual display.
356 *
357 * Code should be locked by {@link #mVdLock} before invoked.
358 *
359 * @param surface The Surface to set.
360 */
361 private void setSurfaceLocked(Surface surface) {
362 // Change the surface to either a valid surface or a null value.
363 if (mSurface != surface && (surface == null || surface.isValid())) {
364 Log.i(TAG, "Setting the new surface from " + mSurface + " to " + surface);
Santos Cordonc14513d2016-12-14 14:52:59 -0800365 if (mVirtualDisplay != null) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700366 mVirtualDisplay.setSurface(surface);
Santos Cordonc14513d2016-12-14 14:52:59 -0800367 }
Santos Cordon975c00d2017-03-21 17:05:36 -0700368 if (mSurface != null) {
369 mSurface.release();
370 }
371 mSurface = surface;
372 }
373 }
374
375 /**
376 * Starts an ImageReader as a do-nothing Surface. The virtual display will not get fully
377 * initialized within surface flinger unless it has a valid Surface associated with it. We use
378 * the ImageReader as the default valid Surface.
379 */
380 private void startImageReader() {
381 if (mImageReader == null) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700382 mImageReader = ImageReader.newInstance(mVirtualDisplayWidth, mVirtualDisplayHeight,
383 PixelFormat.RGBA_8888, 2 /* maxImages */);
384 Log.i(TAG, "VD startImageReader: res = " + mVirtualDisplayWidth + "X" +
385 mVirtualDisplayHeight + ", dpi = " + mVirtualDisplayDpi);
Santos Cordon975c00d2017-03-21 17:05:36 -0700386 }
387 synchronized (mVdLock) {
388 setSurfaceLocked(mImageReader.getSurface());
Santos Cordonc14513d2016-12-14 14:52:59 -0800389 }
390 }
Santos Cordon728d81f2017-04-12 15:20:33 -0700391
392 /**
393 * Cleans up the ImageReader.
394 */
395 private void stopImageReader() {
396 if (mImageReader != null) {
397 mImageReader.close();
398 mImageReader = null;
399 }
400 }
Santos Cordon627a68f2017-06-12 17:57:17 -0700401
402 private boolean shouldRunVirtualDisplay() {
Santos Cordonc22c5632017-06-21 16:03:49 -0700403 // Virtual Display should run whenever:
404 // * Virtual Display is allowed/enabled AND
405 // (1) BootsToVr is set indicating the device never leaves VR
406 // (2) VR (persistent) mode is enabled
407 // (3) VR mode is overridden to be enabled.
408 return mIsVirtualDisplayAllowed &&
409 (mBootsToVr || mIsPersistentVrModeEnabled || mIsVrModeOverrideEnabled);
Santos Cordon627a68f2017-06-12 17:57:17 -0700410 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800411}