1c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonpackage com.android.server.vr;
2c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
33a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankarimport static android.view.Display.INVALID_DISPLAY;
43a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar
599493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankarimport android.app.ActivityManagerInternal;
62b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankarimport android.app.Vr2dDisplayProperties;
7c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.app.Service;
82f22da701b16f748abaeedd65be5ce5898abc824Santos Cordonimport android.content.BroadcastReceiver;
9c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.content.Context;
10c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.content.Intent;
112f22da701b16f748abaeedd65be5ce5898abc824Santos Cordonimport android.content.IntentFilter;
125a2ca72e389435b2419b64912af1d49a20b3cd35Daniel Nicoaraimport android.graphics.PixelFormat;
13c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.hardware.display.DisplayManager;
14c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.hardware.display.VirtualDisplay;
15975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordonimport android.media.ImageReader;
16c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.os.Build;
17c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.os.Handler;
18c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.os.IBinder;
19975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordonimport android.os.Message;
20c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.os.RemoteException;
21c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.os.ServiceManager;
22975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordonimport android.os.SystemProperties;
23975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordonimport android.service.vr.IPersistentVrStateCallbacks;
24c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.service.vr.IVrManager;
25c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport android.util.Log;
262f22da701b16f748abaeedd65be5ce5898abc824Santos Cordonimport android.view.Surface;
27c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
28c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordonimport com.android.server.vr.VrManagerService;
29c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
30c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon/**
31c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
32c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR.
33c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon */
342b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankarclass Vr2dDisplay {
352b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar    private final static String TAG = "Vr2dDisplay";
36c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private final static boolean DEBUG = false;
37c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
38c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    // TODO: Go over these values and figure out what is best
39cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    private int mVirtualDisplayHeight;
40cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    private int mVirtualDisplayWidth;
41cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    private int mVirtualDisplayDpi;
42975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
43b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon    private final static String UNIQUE_DISPLAY_ID = "277f1a09-b88d-4d1e-8716-796f114d080b";
44b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon    private final static String DISPLAY_NAME = "VR 2D Display";
45c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
462f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private final static String DEBUG_ACTION_SET_MODE =
472b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar            "com.android.server.vr.Vr2dDisplay.SET_MODE";
482f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private final static String DEBUG_EXTRA_MODE_ON =
492b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar            "com.android.server.vr.Vr2dDisplay.EXTRA_MODE_ON";
502f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private final static String DEBUG_ACTION_SET_SURFACE =
512b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar            "com.android.server.vr.Vr2dDisplay.SET_SURFACE";
522f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private final static String DEBUG_EXTRA_SURFACE =
532b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar            "com.android.server.vr.Vr2dDisplay.EXTRA_SURFACE";
542f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon
55cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    /**
56cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * The default width of the VR virtual display
57cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     */
58cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int DEFAULT_VR_DISPLAY_WIDTH = 1400;
59cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
60cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    /**
61cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * The default height of the VR virtual display
62cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     */
63cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int DEFAULT_VR_DISPLAY_HEIGHT = 1800;
64cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
65cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    /**
66cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * The default height of the VR virtual dpi.
67cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     */
68cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int DEFAULT_VR_DISPLAY_DPI = 320;
69cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
70cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    /**
71cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * The minimum height, width and dpi of VR virtual display.
72cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     */
73cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int MIN_VR_DISPLAY_WIDTH = 1;
74cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int MIN_VR_DISPLAY_HEIGHT = 1;
75cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    public static final int MIN_VR_DISPLAY_DPI = 1;
76cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
7799493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar    private final ActivityManagerInternal mActivityManagerInternal;
78c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private final DisplayManager mDisplayManager;
79c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private final IVrManager mVrManager;
80975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private final Object mVdLock = new Object();
81975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private final Handler mHandler = new Handler();
82c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
83975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
84975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Callback implementation to receive changes to VrMode.
85975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     **/
86975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private final IPersistentVrStateCallbacks mVrStateCallbacks =
87975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            new IPersistentVrStateCallbacks.Stub() {
88c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        @Override
89975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        public void onPersistentVrStateChanged(boolean enabled) {
90c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            if (enabled != mIsVrModeEnabled) {
91c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon                mIsVrModeEnabled = enabled;
922f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                updateVirtualDisplay();
93c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            }
94c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
95c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    };
96c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
97c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private VirtualDisplay mVirtualDisplay;
982f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private Surface mSurface;
99975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private ImageReader mImageReader;
100975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private Runnable mStopVDRunnable;
101975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private boolean mIsVrModeOverrideEnabled;
102c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private boolean mIsVrModeEnabled;
103c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
1042b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar    public Vr2dDisplay(DisplayManager displayManager,
10599493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar           ActivityManagerInternal activityManagerInternal, IVrManager vrManager) {
106c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        mDisplayManager = displayManager;
10799493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar        mActivityManagerInternal = activityManagerInternal;
108c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        mVrManager = vrManager;
109cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        mVirtualDisplayWidth = DEFAULT_VR_DISPLAY_WIDTH;
110cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        mVirtualDisplayHeight = DEFAULT_VR_DISPLAY_HEIGHT;
111cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        mVirtualDisplayDpi = DEFAULT_VR_DISPLAY_DPI;
112c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    }
113c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
114c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    /**
115c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon     * Initializes the compabilitiy display by listening to VR mode changes.
116c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon     */
1172f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    public void init(Context context) {
118c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        startVrModeListener();
1192f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon        startDebugOnlyBroadcastReceiver(context);
1202f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    }
1212f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon
122975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
123975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Creates and Destroys the virtual display depending on the current state of VrMode.
124975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
1252f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private void updateVirtualDisplay() {
126975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        if (DEBUG) {
1275dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon            Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", override: " + mIsVrModeOverrideEnabled);
128975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        }
129975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon
1305dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon        if (mIsVrModeEnabled || mIsVrModeOverrideEnabled) {
1312f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            // TODO: Consider not creating the display until ActivityManager needs one on
1322f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            // which to display a 2D application.
1335dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon            startVirtualDisplay();
1342f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon        } else {
1353a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar            // Stop virtual display to test exit condition
1363a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar            stopVirtualDisplay();
1372f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon        }
1382f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    }
1392f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon
140975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
141975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Creates a DEBUG-only BroadcastReceiver through which a test app can simulate VrMode and
142975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * set a custom Surface for the virtual display.  This allows testing of the virtual display
143975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * without going into full 3D.
144975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     *
145975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * @param context The context.
146975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
1472f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon    private void startDebugOnlyBroadcastReceiver(Context context) {
1485dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon        if (DEBUG) {
1492f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            IntentFilter intentFilter = new IntentFilter(DEBUG_ACTION_SET_MODE);
1502f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            intentFilter.addAction(DEBUG_ACTION_SET_SURFACE);
1512f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon
1522f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            context.registerReceiver(new BroadcastReceiver() {
1532f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                @Override
1542f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                public void onReceive(Context context, Intent intent) {
1552f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                    final String action = intent.getAction();
1562f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                    if (DEBUG_ACTION_SET_MODE.equals(action)) {
157975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                        mIsVrModeOverrideEnabled =
1582f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                                intent.getBooleanExtra(DEBUG_EXTRA_MODE_ON, false);
1592f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                        updateVirtualDisplay();
1602f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                    } else if (DEBUG_ACTION_SET_SURFACE.equals(action)) {
1612f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                        if (mVirtualDisplay != null) {
162975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                            if (intent.hasExtra(DEBUG_EXTRA_SURFACE)) {
163975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                                setSurfaceLocked(intent.getParcelableExtra(DEBUG_EXTRA_SURFACE));
1642f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                            }
1652f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                        } else {
1662f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                            Log.w(TAG, "Cannot set the surface because the VD is null.");
1672f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                        }
1682f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                    }
1692f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                }
1702f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            }, intentFilter);
1712f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon        }
172c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    }
173c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
174975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
175975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Starts listening to VrMode changes.
176975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
177c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private void startVrModeListener() {
178c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        if (mVrManager != null) {
179c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            try {
180975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                mVrManager.registerPersistentVrStateListener(mVrStateCallbacks);
181c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            } catch (RemoteException e) {
182c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon                Log.e(TAG, "Could not register VR State listener.", e);
183c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            }
184c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
185c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    }
186c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
187975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
1882b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar     * Sets the resolution and DPI of the Vr2d virtual display used to display
189cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * 2D applications in VR mode.
190cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     *
191cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
192cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     *
193cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * @param compatDisplayProperties Properties of the virtual display for 2D applications
194cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     * in VR mode.
195cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar     */
1962b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar    public void setVirtualDisplayProperties(Vr2dDisplayProperties compatDisplayProperties) {
197cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        synchronized(mVdLock) {
198cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            if (DEBUG) {
1995dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                Log.i(TAG, "VD setVirtualDisplayProperties: res = "
2005dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + compatDisplayProperties.getWidth() + "X"
2015dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + compatDisplayProperties.getHeight() + ", dpi = "
2025dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + compatDisplayProperties.getDpi());
203cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            }
204cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
205cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            if (compatDisplayProperties.getWidth() < MIN_VR_DISPLAY_WIDTH ||
206cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                compatDisplayProperties.getHeight() < MIN_VR_DISPLAY_HEIGHT ||
207cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                compatDisplayProperties.getDpi() < MIN_VR_DISPLAY_DPI) {
208cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                throw new IllegalArgumentException (
2095dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        "Illegal argument: height, width, dpi cannot be negative. res = "
2105dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + compatDisplayProperties.getWidth() + "X"
2115dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + compatDisplayProperties.getHeight()
2125dc6019bb423f662685b026e65779ebd8897c7c2Santos Cordon                        + ", dpi = " + compatDisplayProperties.getDpi());
213cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            }
214cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
215cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            mVirtualDisplayWidth = compatDisplayProperties.getWidth();
216cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            mVirtualDisplayHeight = compatDisplayProperties.getHeight();
217cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            mVirtualDisplayDpi = compatDisplayProperties.getDpi();
218cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
219cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            if (mVirtualDisplay != null) {
220cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                mVirtualDisplay.resize(mVirtualDisplayWidth, mVirtualDisplayHeight,
221cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                    mVirtualDisplayDpi);
222cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                ImageReader oldImageReader = mImageReader;
223cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                mImageReader = null;
224cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                startImageReader();
225cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                oldImageReader.close();
226cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            }
227cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        }
228cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    }
229cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar
230cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar    /**
231975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Returns the virtual display ID if one currently exists, otherwise returns
232975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * {@link INVALID_DISPLAY_ID}.
233975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     *
234975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * @return The virtual display ID.
235975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
2363a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar    public int getVirtualDisplayId() {
237975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        synchronized(mVdLock) {
2383a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar            if (mVirtualDisplay != null) {
2393a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar                int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
2403a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar                if (DEBUG) {
241cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                    Log.i(TAG, "VD id: " + virtualDisplayId);
2423a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar                }
2433a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar                return virtualDisplayId;
2443a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar            }
2453a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar        }
2463a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar        return INVALID_DISPLAY;
2473a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar    }
2483a47ec2edd04546d82ba1df331c7af778858a281Karthik Ravi Shankar
249975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
250975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Starts the virtual display if one does not already exist.
251975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
252c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private void startVirtualDisplay() {
253c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        if (DEBUG) {
2542f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon            Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
255c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
256c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
257c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        if (mDisplayManager == null) {
258c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            Log.w(TAG, "Cannot create virtual display because mDisplayManager == null");
259c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            return;
260c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
261c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
262975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        synchronized (mVdLock) {
263c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            if (mVirtualDisplay != null) {
2642f22da701b16f748abaeedd65be5ce5898abc824Santos Cordon                Log.i(TAG, "VD already exists, ignoring request");
265c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon                return;
266c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            }
267c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
268b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon            int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
269b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon            mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
270b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon                    DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
271b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon                    null /* surface */, flags, null /* callback */, null /* handler */,
272b0608636a29bcec8ecb4391cd50f29f68b3e7e81Santos Cordon                    UNIQUE_DISPLAY_ID);
27399493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar
27499493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar            if (mVirtualDisplay != null) {
2752b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar                mActivityManagerInternal.setVr2dDisplayId(
27699493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar                    mVirtualDisplay.getDisplay().getDisplayId());
277728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon                // Now create the ImageReader to supply a Surface to the new virtual display.
278728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon                startImageReader();
27999493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar            } else {
28099493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar                Log.w(TAG, "Virtual display id is null after createVirtualDisplay");
2812b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar                mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY);
28299493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar                return;
28399493dbc94989d4493ca6acb0db265a02f49f62eKarthik Ravi Shankar            }
284c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
285c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
286cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar        Log.i(TAG, "VD created: " + mVirtualDisplay);
287c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    }
288c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
289975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
290975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Stops the virtual display with a {@link #STOP_VIRTUAL_DISPLAY_DELAY_MILLIS} timeout.
291975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * The timeout prevents the virtual display from bouncing in cases where VrMode goes in and out
292975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * of being enabled. This can happen sometimes with our 2D test app.
293975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
294c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    private void stopVirtualDisplay() {
295975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        if (mStopVDRunnable == null) {
296975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon           mStopVDRunnable = new Runnable() {
297975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon               @Override
298975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon               public void run() {
299975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                    if (mIsVrModeEnabled) {
300975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                        Log.i(TAG, "Virtual Display destruction stopped: VrMode is back on.");
301975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                    } else {
302975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                        Log.i(TAG, "Stopping Virtual Display");
303975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                        synchronized (mVdLock) {
3042b9aaedf6310694de31301659ce604ff195b32eeKarthik Ravi Shankar                            mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY);
305975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                            setSurfaceLocked(null); // clean up and release the surface first.
306975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                            if (mVirtualDisplay != null) {
307975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                                mVirtualDisplay.release();
308975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                                mVirtualDisplay = null;
309975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                            }
310728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon                            stopImageReader();
311975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                        }
312975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                    }
313975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon               }
314975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon           };
315c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
316c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon
317975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        mHandler.removeCallbacks(mStopVDRunnable);
318975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        mHandler.postDelayed(mStopVDRunnable, STOP_VIRTUAL_DISPLAY_DELAY_MILLIS);
319975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    }
320975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon
321975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
322975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Set the surface to use with the virtual display.
323975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     *
324975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Code should be locked by {@link #mVdLock} before invoked.
325975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     *
326975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * @param surface The Surface to set.
327975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
328975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private void setSurfaceLocked(Surface surface) {
329975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        // Change the surface to either a valid surface or a null value.
330975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        if (mSurface != surface && (surface == null || surface.isValid())) {
331975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            Log.i(TAG, "Setting the new surface from " + mSurface + " to " + surface);
332c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            if (mVirtualDisplay != null) {
333975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                mVirtualDisplay.setSurface(surface);
334975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            }
335975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            if (mSurface != null) {
336975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon                mSurface.release();
337c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon            }
338975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            mSurface = surface;
339975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        }
340975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    }
341975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon
342975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    /**
343975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * Starts an ImageReader as a do-nothing Surface.  The virtual display will not get fully
344975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * initialized within surface flinger unless it has a valid Surface associated with it. We use
345975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     * the ImageReader as the default valid Surface.
346975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon     */
347975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon    private void startImageReader() {
348975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        if (mImageReader == null) {
349cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            mImageReader = ImageReader.newInstance(mVirtualDisplayWidth, mVirtualDisplayHeight,
350cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                PixelFormat.RGBA_8888, 2 /* maxImages */);
351cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar            Log.i(TAG, "VD startImageReader: res = " + mVirtualDisplayWidth + "X" +
352cdf9ce7229e791fe345b0860fe32433f15c95db8Karthik Ravi Shankar                    mVirtualDisplayHeight + ", dpi = " + mVirtualDisplayDpi);
353975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        }
354975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon        synchronized (mVdLock) {
355975c00d8ffeeb72a05bc229e0e1234e771c4a824Santos Cordon            setSurfaceLocked(mImageReader.getSurface());
356c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon        }
357c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon    }
358728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon
359728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon    /**
360728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon     * Cleans up the ImageReader.
361728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon     */
362728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon    private void stopImageReader() {
363728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon        if (mImageReader != null) {
364728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon            mImageReader.close();
365728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon            mImageReader = null;
366728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon        }
367728d81f67326ad0c2f468d1da560936b5ffb90a0Santos Cordon    }
368c14513d81ef22cfbab93a9209f237534b3b5edc8Santos Cordon}
369