blob: 7866e7d4493836073c5c9f7f5292acd879b4102f [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 Cordonc14513d2016-12-14 14:52:59 -08007import android.app.Service;
Santos Cordon2f22da72017-02-27 17:24:44 -08008import android.content.BroadcastReceiver;
Santos Cordonc14513d2016-12-14 14:52:59 -08009import android.content.Context;
10import android.content.Intent;
Santos Cordon2f22da72017-02-27 17:24:44 -080011import android.content.IntentFilter;
Daniel Nicoara5a2ca722017-04-05 17:38:16 -040012import android.graphics.PixelFormat;
Santos Cordonc14513d2016-12-14 14:52:59 -080013import android.hardware.display.DisplayManager;
14import android.hardware.display.VirtualDisplay;
Santos Cordon975c00d2017-03-21 17:05:36 -070015import android.media.ImageReader;
Santos Cordonc14513d2016-12-14 14:52:59 -080016import android.os.Build;
17import android.os.Handler;
18import android.os.IBinder;
Santos Cordon975c00d2017-03-21 17:05:36 -070019import android.os.Message;
Santos Cordonc14513d2016-12-14 14:52:59 -080020import android.os.RemoteException;
21import android.os.ServiceManager;
Santos Cordon975c00d2017-03-21 17:05:36 -070022import android.os.SystemProperties;
23import android.service.vr.IPersistentVrStateCallbacks;
Santos Cordonc14513d2016-12-14 14:52:59 -080024import android.service.vr.IVrManager;
25import android.util.Log;
Santos Cordon2f22da72017-02-27 17:24:44 -080026import android.view.Surface;
Santos Cordonc14513d2016-12-14 14:52:59 -080027
Adrian Roose99bc052017-11-20 17:55:31 +010028import com.android.server.wm.WindowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -080029
30/**
31 * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
32 * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR.
33 */
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070034class Vr2dDisplay {
35 private final static String TAG = "Vr2dDisplay";
Santos Cordonc14513d2016-12-14 14:52:59 -080036 private final static boolean DEBUG = false;
37
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070038 private int mVirtualDisplayHeight;
39 private int mVirtualDisplayWidth;
40 private int mVirtualDisplayDpi;
Santos Cordon975c00d2017-03-21 17:05:36 -070041 private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
Santos Cordonb0608632017-04-05 10:31:15 -070042 private final static String UNIQUE_DISPLAY_ID = "277f1a09-b88d-4d1e-8716-796f114d080b";
43 private final static String DISPLAY_NAME = "VR 2D Display";
Santos Cordonc14513d2016-12-14 14:52:59 -080044
Santos Cordon2f22da72017-02-27 17:24:44 -080045 private final static String DEBUG_ACTION_SET_MODE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070046 "com.android.server.vr.Vr2dDisplay.SET_MODE";
Santos Cordon2f22da72017-02-27 17:24:44 -080047 private final static String DEBUG_EXTRA_MODE_ON =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070048 "com.android.server.vr.Vr2dDisplay.EXTRA_MODE_ON";
Santos Cordon2f22da72017-02-27 17:24:44 -080049 private final static String DEBUG_ACTION_SET_SURFACE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070050 "com.android.server.vr.Vr2dDisplay.SET_SURFACE";
Santos Cordon2f22da72017-02-27 17:24:44 -080051 private final static String DEBUG_EXTRA_SURFACE =
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -070052 "com.android.server.vr.Vr2dDisplay.EXTRA_SURFACE";
Santos Cordon2f22da72017-02-27 17:24:44 -080053
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070054 /**
55 * The default width of the VR virtual display
56 */
Santos Cordonc22c5632017-06-21 16:03:49 -070057 public static final int DEFAULT_VIRTUAL_DISPLAY_WIDTH = 1400;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070058
59 /**
60 * The default height of the VR virtual display
61 */
Karthik Ravi Shankar6d1575f2017-07-06 10:23:57 -070062 public static final int DEFAULT_VIRTUAL_DISPLAY_HEIGHT = 1800;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070063
64 /**
65 * The default height of the VR virtual dpi.
66 */
Santos Cordonc22c5632017-06-21 16:03:49 -070067 public static final int DEFAULT_VIRTUAL_DISPLAY_DPI = 320;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -070068
69 /**
70 * The minimum height, width and dpi of VR virtual display.
71 */
72 public static final int MIN_VR_DISPLAY_WIDTH = 1;
73 public static final int MIN_VR_DISPLAY_HEIGHT = 1;
74 public static final int MIN_VR_DISPLAY_DPI = 1;
75
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -080076 private final ActivityManagerInternal mActivityManagerInternal;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070077 private final WindowManagerInternal mWindowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -080078 private final DisplayManager mDisplayManager;
79 private final IVrManager mVrManager;
Santos Cordon975c00d2017-03-21 17:05:36 -070080 private final Object mVdLock = new Object();
81 private final Handler mHandler = new Handler();
Santos Cordonc14513d2016-12-14 14:52:59 -080082
Santos Cordon975c00d2017-03-21 17:05:36 -070083 /**
84 * Callback implementation to receive changes to VrMode.
85 **/
86 private final IPersistentVrStateCallbacks mVrStateCallbacks =
87 new IPersistentVrStateCallbacks.Stub() {
Santos Cordonc14513d2016-12-14 14:52:59 -080088 @Override
Santos Cordon975c00d2017-03-21 17:05:36 -070089 public void onPersistentVrStateChanged(boolean enabled) {
Santos Cordonc22c5632017-06-21 16:03:49 -070090 if (enabled != mIsPersistentVrModeEnabled) {
91 mIsPersistentVrModeEnabled = enabled;
Santos Cordon2f22da72017-02-27 17:24:44 -080092 updateVirtualDisplay();
Santos Cordonc14513d2016-12-14 14:52:59 -080093 }
94 }
95 };
96
97 private VirtualDisplay mVirtualDisplay;
Santos Cordon2f22da72017-02-27 17:24:44 -080098 private Surface mSurface;
Santos Cordon975c00d2017-03-21 17:05:36 -070099 private ImageReader mImageReader;
100 private Runnable mStopVDRunnable;
Santos Cordonc22c5632017-06-21 16:03:49 -0700101 private boolean mIsVrModeOverrideEnabled; // debug override to set vr mode.
102 private boolean mIsVirtualDisplayAllowed = true; // Virtual-display feature toggle
103 private boolean mIsPersistentVrModeEnabled; // indicates we are in vr persistent mode.
104 private boolean mBootsToVr = false; // The device boots into VR (standalone VR device)
Santos Cordonc14513d2016-12-14 14:52:59 -0800105
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -0700106 public Vr2dDisplay(DisplayManager displayManager,
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700107 ActivityManagerInternal activityManagerInternal,
108 WindowManagerInternal windowManagerInternal, IVrManager vrManager) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800109 mDisplayManager = displayManager;
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800110 mActivityManagerInternal = activityManagerInternal;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700111 mWindowManagerInternal = windowManagerInternal;
Santos Cordonc14513d2016-12-14 14:52:59 -0800112 mVrManager = vrManager;
Santos Cordonc22c5632017-06-21 16:03:49 -0700113 mVirtualDisplayWidth = DEFAULT_VIRTUAL_DISPLAY_WIDTH;
114 mVirtualDisplayHeight = DEFAULT_VIRTUAL_DISPLAY_HEIGHT;
115 mVirtualDisplayDpi = DEFAULT_VIRTUAL_DISPLAY_DPI;
Santos Cordonc14513d2016-12-14 14:52:59 -0800116 }
117
118 /**
119 * Initializes the compabilitiy display by listening to VR mode changes.
120 */
Santos Cordonc22c5632017-06-21 16:03:49 -0700121 public void init(Context context, boolean bootsToVr) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800122 startVrModeListener();
Santos Cordon2f22da72017-02-27 17:24:44 -0800123 startDebugOnlyBroadcastReceiver(context);
Santos Cordonc22c5632017-06-21 16:03:49 -0700124 mBootsToVr = bootsToVr;
125 if (mBootsToVr) {
126 // If we are booting into VR, we need to start the virtual display immediately. This
127 // ensures that the virtual display is up by the time Setup Wizard is started.
128 updateVirtualDisplay();
129 }
Santos Cordon2f22da72017-02-27 17:24:44 -0800130 }
131
Santos Cordon975c00d2017-03-21 17:05:36 -0700132 /**
133 * Creates and Destroys the virtual display depending on the current state of VrMode.
134 */
Santos Cordon2f22da72017-02-27 17:24:44 -0800135 private void updateVirtualDisplay() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700136 if (DEBUG) {
Santos Cordonc22c5632017-06-21 16:03:49 -0700137 Log.i(TAG, "isVrMode: " + mIsPersistentVrModeEnabled + ", override: "
138 + mIsVrModeOverrideEnabled + ", isAllowed: " + mIsVirtualDisplayAllowed
139 + ", bootsToVr: " + mBootsToVr);
Santos Cordon975c00d2017-03-21 17:05:36 -0700140 }
141
Santos Cordon627a68f2017-06-12 17:57:17 -0700142 if (shouldRunVirtualDisplay()) {
Santos Cordonc22c5632017-06-21 16:03:49 -0700143 Log.i(TAG, "Attempting to start virtual display");
Santos Cordon2f22da72017-02-27 17:24:44 -0800144 // TODO: Consider not creating the display until ActivityManager needs one on
145 // which to display a 2D application.
Santos Cordon5dc60192017-05-09 11:36:53 -0700146 startVirtualDisplay();
Santos Cordon2f22da72017-02-27 17:24:44 -0800147 } else {
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800148 // Stop virtual display to test exit condition
149 stopVirtualDisplay();
Santos Cordon2f22da72017-02-27 17:24:44 -0800150 }
151 }
152
Santos Cordon975c00d2017-03-21 17:05:36 -0700153 /**
154 * Creates a DEBUG-only BroadcastReceiver through which a test app can simulate VrMode and
155 * set a custom Surface for the virtual display. This allows testing of the virtual display
156 * without going into full 3D.
157 *
158 * @param context The context.
159 */
Santos Cordon2f22da72017-02-27 17:24:44 -0800160 private void startDebugOnlyBroadcastReceiver(Context context) {
Santos Cordon5dc60192017-05-09 11:36:53 -0700161 if (DEBUG) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800162 IntentFilter intentFilter = new IntentFilter(DEBUG_ACTION_SET_MODE);
163 intentFilter.addAction(DEBUG_ACTION_SET_SURFACE);
164
165 context.registerReceiver(new BroadcastReceiver() {
166 @Override
167 public void onReceive(Context context, Intent intent) {
168 final String action = intent.getAction();
169 if (DEBUG_ACTION_SET_MODE.equals(action)) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700170 mIsVrModeOverrideEnabled =
Santos Cordon2f22da72017-02-27 17:24:44 -0800171 intent.getBooleanExtra(DEBUG_EXTRA_MODE_ON, false);
172 updateVirtualDisplay();
173 } else if (DEBUG_ACTION_SET_SURFACE.equals(action)) {
174 if (mVirtualDisplay != null) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700175 if (intent.hasExtra(DEBUG_EXTRA_SURFACE)) {
176 setSurfaceLocked(intent.getParcelableExtra(DEBUG_EXTRA_SURFACE));
Santos Cordon2f22da72017-02-27 17:24:44 -0800177 }
178 } else {
179 Log.w(TAG, "Cannot set the surface because the VD is null.");
180 }
181 }
182 }
183 }, intentFilter);
184 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800185 }
186
Santos Cordon975c00d2017-03-21 17:05:36 -0700187 /**
188 * Starts listening to VrMode changes.
189 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800190 private void startVrModeListener() {
191 if (mVrManager != null) {
192 try {
Santos Cordon975c00d2017-03-21 17:05:36 -0700193 mVrManager.registerPersistentVrStateListener(mVrStateCallbacks);
Santos Cordonc14513d2016-12-14 14:52:59 -0800194 } catch (RemoteException e) {
195 Log.e(TAG, "Could not register VR State listener.", e);
196 }
197 }
198 }
199
Santos Cordon975c00d2017-03-21 17:05:36 -0700200 /**
Karthik Ravi Shankar2b9aaed2017-05-01 01:34:19 -0700201 * Sets the resolution and DPI of the Vr2d virtual display used to display
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700202 * 2D applications in VR mode.
203 *
204 * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
205 *
Santos Cordon627a68f2017-06-12 17:57:17 -0700206 * @param displayProperties Properties of the virtual display for 2D applications
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700207 * in VR mode.
208 */
Santos Cordon627a68f2017-06-12 17:57:17 -0700209 public void setVirtualDisplayProperties(Vr2dDisplayProperties displayProperties) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700210 synchronized(mVdLock) {
211 if (DEBUG) {
Santos Cordon627a68f2017-06-12 17:57:17 -0700212 Log.i(TAG, "VD setVirtualDisplayProperties: " +
213 displayProperties.toString());
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700214 }
215
Santos Cordon627a68f2017-06-12 17:57:17 -0700216 int width = displayProperties.getWidth();
217 int height = displayProperties.getHeight();
218 int dpi = displayProperties.getDpi();
219 boolean resized = false;
220
221 if (width < MIN_VR_DISPLAY_WIDTH || height < MIN_VR_DISPLAY_HEIGHT ||
222 dpi < MIN_VR_DISPLAY_DPI) {
223 Log.i(TAG, "Ignoring Width/Height/Dpi values of " + width + "," + height + ","
224 + dpi);
225 } else {
226 Log.i(TAG, "Setting width/height/dpi to " + width + "," + height + "," + dpi);
227 mVirtualDisplayWidth = width;
228 mVirtualDisplayHeight = height;
229 mVirtualDisplayDpi = dpi;
230 resized = true;
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700231 }
232
Santos Cordon627a68f2017-06-12 17:57:17 -0700233 if ((displayProperties.getFlags() & Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
234 == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
235 mIsVirtualDisplayAllowed = true;
236 } else if ((displayProperties.getRemovedFlags() &
237 Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
238 == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
239 mIsVirtualDisplayAllowed = false;
240 }
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700241
Santos Cordon627a68f2017-06-12 17:57:17 -0700242 if (mVirtualDisplay != null && resized && mIsVirtualDisplayAllowed) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700243 mVirtualDisplay.resize(mVirtualDisplayWidth, mVirtualDisplayHeight,
244 mVirtualDisplayDpi);
245 ImageReader oldImageReader = mImageReader;
246 mImageReader = null;
247 startImageReader();
248 oldImageReader.close();
249 }
Santos Cordon627a68f2017-06-12 17:57:17 -0700250
251 // Start/Stop the virtual display in case the updates indicated that we should.
252 updateVirtualDisplay();
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700253 }
254 }
255
256 /**
Santos Cordon975c00d2017-03-21 17:05:36 -0700257 * Returns the virtual display ID if one currently exists, otherwise returns
258 * {@link INVALID_DISPLAY_ID}.
259 *
260 * @return The virtual display ID.
261 */
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800262 public int getVirtualDisplayId() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700263 synchronized(mVdLock) {
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800264 if (mVirtualDisplay != null) {
265 int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
266 if (DEBUG) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700267 Log.i(TAG, "VD id: " + virtualDisplayId);
Karthik Ravi Shankar3a47ec22017-03-08 18:09:35 -0800268 }
269 return virtualDisplayId;
270 }
271 }
272 return INVALID_DISPLAY;
273 }
274
Santos Cordon975c00d2017-03-21 17:05:36 -0700275 /**
276 * Starts the virtual display if one does not already exist.
277 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800278 private void startVirtualDisplay() {
279 if (DEBUG) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800280 Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
Santos Cordonc14513d2016-12-14 14:52:59 -0800281 }
282
283 if (mDisplayManager == null) {
284 Log.w(TAG, "Cannot create virtual display because mDisplayManager == null");
285 return;
286 }
287
Santos Cordon975c00d2017-03-21 17:05:36 -0700288 synchronized (mVdLock) {
Santos Cordonc14513d2016-12-14 14:52:59 -0800289 if (mVirtualDisplay != null) {
Santos Cordon2f22da72017-02-27 17:24:44 -0800290 Log.i(TAG, "VD already exists, ignoring request");
Santos Cordonc14513d2016-12-14 14:52:59 -0800291 return;
292 }
293
Santos Cordonb0608632017-04-05 10:31:15 -0700294 int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
Alex Sakhartchouk879d24f2017-06-20 22:01:19 -0400295 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
Karthik Ravi Shankar4c657382017-09-26 13:40:58 -0700296 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
297 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
rongliu1e90fc32017-10-04 17:30:30 -0700298 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
Santos Cordonb0608632017-04-05 10:31:15 -0700299 mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
300 DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
301 null /* surface */, flags, null /* callback */, null /* handler */,
302 UNIQUE_DISPLAY_ID);
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800303
304 if (mVirtualDisplay != null) {
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700305 updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
Santos Cordon728d81f2017-04-12 15:20:33 -0700306 // Now create the ImageReader to supply a Surface to the new virtual display.
307 startImageReader();
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800308 } else {
309 Log.w(TAG, "Virtual display id is null after createVirtualDisplay");
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700310 updateDisplayId(INVALID_DISPLAY);
Karthik Ravi Shankar99493db2017-03-08 18:30:19 -0800311 return;
312 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800313 }
314
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700315 Log.i(TAG, "VD created: " + mVirtualDisplay);
Santos Cordonc14513d2016-12-14 14:52:59 -0800316 }
317
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700318 private void updateDisplayId(int displayId) {
319 mActivityManagerInternal.setVr2dDisplayId(displayId);
320 mWindowManagerInternal.setVr2dDisplayId(displayId);
321 }
322
Santos Cordon975c00d2017-03-21 17:05:36 -0700323 /**
324 * Stops the virtual display with a {@link #STOP_VIRTUAL_DISPLAY_DELAY_MILLIS} timeout.
325 * The timeout prevents the virtual display from bouncing in cases where VrMode goes in and out
326 * of being enabled. This can happen sometimes with our 2D test app.
327 */
Santos Cordonc14513d2016-12-14 14:52:59 -0800328 private void stopVirtualDisplay() {
Santos Cordon975c00d2017-03-21 17:05:36 -0700329 if (mStopVDRunnable == null) {
330 mStopVDRunnable = new Runnable() {
331 @Override
332 public void run() {
Santos Cordon627a68f2017-06-12 17:57:17 -0700333 if (shouldRunVirtualDisplay()) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700334 Log.i(TAG, "Virtual Display destruction stopped: VrMode is back on.");
335 } else {
336 Log.i(TAG, "Stopping Virtual Display");
337 synchronized (mVdLock) {
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700338 updateDisplayId(INVALID_DISPLAY);
Santos Cordon975c00d2017-03-21 17:05:36 -0700339 setSurfaceLocked(null); // clean up and release the surface first.
340 if (mVirtualDisplay != null) {
341 mVirtualDisplay.release();
342 mVirtualDisplay = null;
343 }
Santos Cordon728d81f2017-04-12 15:20:33 -0700344 stopImageReader();
Santos Cordon975c00d2017-03-21 17:05:36 -0700345 }
346 }
347 }
348 };
Santos Cordonc14513d2016-12-14 14:52:59 -0800349 }
350
Santos Cordon975c00d2017-03-21 17:05:36 -0700351 mHandler.removeCallbacks(mStopVDRunnable);
352 mHandler.postDelayed(mStopVDRunnable, STOP_VIRTUAL_DISPLAY_DELAY_MILLIS);
353 }
354
355 /**
356 * Set the surface to use with the virtual display.
357 *
358 * Code should be locked by {@link #mVdLock} before invoked.
359 *
360 * @param surface The Surface to set.
361 */
362 private void setSurfaceLocked(Surface surface) {
363 // Change the surface to either a valid surface or a null value.
364 if (mSurface != surface && (surface == null || surface.isValid())) {
365 Log.i(TAG, "Setting the new surface from " + mSurface + " to " + surface);
Santos Cordonc14513d2016-12-14 14:52:59 -0800366 if (mVirtualDisplay != null) {
Santos Cordon975c00d2017-03-21 17:05:36 -0700367 mVirtualDisplay.setSurface(surface);
Santos Cordonc14513d2016-12-14 14:52:59 -0800368 }
Santos Cordon975c00d2017-03-21 17:05:36 -0700369 if (mSurface != null) {
370 mSurface.release();
371 }
372 mSurface = surface;
373 }
374 }
375
376 /**
377 * Starts an ImageReader as a do-nothing Surface. The virtual display will not get fully
378 * initialized within surface flinger unless it has a valid Surface associated with it. We use
379 * the ImageReader as the default valid Surface.
380 */
381 private void startImageReader() {
382 if (mImageReader == null) {
Karthik Ravi Shankarcdf9ce72017-04-12 15:31:20 -0700383 mImageReader = ImageReader.newInstance(mVirtualDisplayWidth, mVirtualDisplayHeight,
384 PixelFormat.RGBA_8888, 2 /* maxImages */);
385 Log.i(TAG, "VD startImageReader: res = " + mVirtualDisplayWidth + "X" +
386 mVirtualDisplayHeight + ", dpi = " + mVirtualDisplayDpi);
Santos Cordon975c00d2017-03-21 17:05:36 -0700387 }
388 synchronized (mVdLock) {
389 setSurfaceLocked(mImageReader.getSurface());
Santos Cordonc14513d2016-12-14 14:52:59 -0800390 }
391 }
Santos Cordon728d81f2017-04-12 15:20:33 -0700392
393 /**
394 * Cleans up the ImageReader.
395 */
396 private void stopImageReader() {
397 if (mImageReader != null) {
398 mImageReader.close();
399 mImageReader = null;
400 }
401 }
Santos Cordon627a68f2017-06-12 17:57:17 -0700402
403 private boolean shouldRunVirtualDisplay() {
Santos Cordonc22c5632017-06-21 16:03:49 -0700404 // Virtual Display should run whenever:
405 // * Virtual Display is allowed/enabled AND
406 // (1) BootsToVr is set indicating the device never leaves VR
407 // (2) VR (persistent) mode is enabled
408 // (3) VR mode is overridden to be enabled.
409 return mIsVirtualDisplayAllowed &&
410 (mBootsToVr || mIsPersistentVrModeEnabled || mIsVrModeOverrideEnabled);
Santos Cordon627a68f2017-06-12 17:57:17 -0700411 }
Santos Cordonc14513d2016-12-14 14:52:59 -0800412}