1package android.app;
2
3import android.annotation.NonNull;
4import android.annotation.RequiresPermission;
5import android.annotation.SystemApi;
6import android.annotation.SystemService;
7import android.annotation.TestApi;
8import android.content.ComponentName;
9import android.content.Context;
10import android.os.Handler;
11import android.os.RemoteException;
12import android.service.vr.IPersistentVrStateCallbacks;
13import android.service.vr.IVrManager;
14import android.service.vr.IVrStateCallbacks;
15import android.util.ArrayMap;
16
17import java.util.Map;
18
19/**
20 * Used to control aspects of a devices Virtual Reality (VR) capabilities.
21 * @hide
22 */
23@SystemApi
24@SystemService(Context.VR_SERVICE)
25public class VrManager {
26
27    private static class CallbackEntry {
28        final IVrStateCallbacks mStateCallback = new IVrStateCallbacks.Stub() {
29            @Override
30            public void onVrStateChanged(boolean enabled) {
31                mHandler.post(() -> mCallback.onVrStateChanged(enabled));
32            }
33
34        };
35        final IPersistentVrStateCallbacks mPersistentStateCallback =
36                new IPersistentVrStateCallbacks.Stub() {
37            @Override
38            public void onPersistentVrStateChanged(boolean enabled) {
39                mHandler.post(() -> mCallback.onPersistentVrStateChanged(enabled));
40            }
41        };
42        final VrStateCallback mCallback;
43        final Handler mHandler;
44
45        CallbackEntry(VrStateCallback callback, Handler handler) {
46            mCallback = callback;
47            mHandler = handler;
48        }
49    }
50
51    private final IVrManager mService;
52    private Map<VrStateCallback, CallbackEntry> mCallbackMap = new ArrayMap<>();
53
54    /**
55     * {@hide}
56     */
57    public VrManager(IVrManager service) {
58        mService = service;
59    }
60
61    /**
62     * Registers a callback to be notified of changes to the VR Mode state.
63     *
64     * @param callback The callback to register.
65     * @hide
66     */
67    @RequiresPermission(anyOf = {
68            android.Manifest.permission.RESTRICTED_VR_ACCESS,
69            android.Manifest.permission.ACCESS_VR_STATE
70    })
71    public void registerVrStateCallback(VrStateCallback callback, @NonNull Handler handler) {
72        if (callback == null || mCallbackMap.containsKey(callback)) {
73            return;
74        }
75
76        CallbackEntry entry = new CallbackEntry(callback, handler);
77        mCallbackMap.put(callback, entry);
78        try {
79            mService.registerListener(entry.mStateCallback);
80            mService.registerPersistentVrStateListener(entry.mPersistentStateCallback);
81        } catch (RemoteException e) {
82            try {
83                unregisterVrStateCallback(callback);
84            } catch (Exception ignore) {
85                e.rethrowFromSystemServer();
86            }
87        }
88    }
89
90    /**
91     * Deregisters VR State callbacks.
92     *
93     * @param callback The callback to deregister.
94     * @hide
95     */
96    @RequiresPermission(anyOf = {
97            android.Manifest.permission.RESTRICTED_VR_ACCESS,
98            android.Manifest.permission.ACCESS_VR_STATE
99    })
100    public void unregisterVrStateCallback(VrStateCallback callback) {
101        CallbackEntry entry = mCallbackMap.remove(callback);
102        if (entry != null) {
103            try {
104                mService.unregisterListener(entry.mStateCallback);
105            } catch (RemoteException ignore) {
106                // Dont rethrow exceptions from requests to unregister.
107            }
108
109            try {
110                mService.unregisterPersistentVrStateListener(entry.mPersistentStateCallback);
111            } catch (RemoteException ignore) {
112                // Dont rethrow exceptions from requests to unregister.
113            }
114        }
115    }
116
117    /**
118     * Returns the current VrMode state.
119     * @hide
120     */
121    @RequiresPermission(anyOf = {
122            android.Manifest.permission.RESTRICTED_VR_ACCESS,
123            android.Manifest.permission.ACCESS_VR_STATE
124    })
125    public boolean getVrModeEnabled() {
126        try {
127            return mService.getVrModeState();
128        } catch (RemoteException e) {
129            e.rethrowFromSystemServer();
130        }
131        return false;
132    }
133
134    /**
135     * Returns the current VrMode state.
136     * @hide
137     */
138    @RequiresPermission(anyOf = {
139            android.Manifest.permission.RESTRICTED_VR_ACCESS,
140            android.Manifest.permission.ACCESS_VR_STATE
141    })
142    public boolean getPersistentVrModeEnabled() {
143        try {
144            return mService.getPersistentVrModeEnabled();
145        } catch (RemoteException e) {
146            e.rethrowFromSystemServer();
147        }
148        return false;
149    }
150
151    /**
152     * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
153     * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
154     * by VR viewers to indicate that a device is placed in a VR viewer.
155     *
156     * @see Activity#setVrModeEnabled(boolean, ComponentName)
157     * @param enabled true if the device should be placed in persistent VR mode.
158     */
159    @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
160    public void setPersistentVrModeEnabled(boolean enabled) {
161        try {
162            mService.setPersistentVrModeEnabled(enabled);
163        } catch (RemoteException e) {
164            e.rethrowFromSystemServer();
165        }
166    }
167
168    /**
169     * Sets the resolution and DPI of the vr2d virtual display used to display 2D
170     * applications in VR mode.
171     *
172     * @param vr2dDisplayProp properties to be set to the virtual display for
173     * 2D applications in VR mode.
174     *
175     * {@hide}
176     */
177    @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
178    public void setVr2dDisplayProperties(
179            Vr2dDisplayProperties vr2dDisplayProp) {
180        try {
181            mService.setVr2dDisplayProperties(vr2dDisplayProp);
182        } catch (RemoteException e) {
183            e.rethrowFromSystemServer();
184        }
185    }
186
187    /**
188     * Set the component name of the compositor service to bind.
189     *
190     * @param componentName ComponentName of a Service in the application's compositor process to
191     * bind to, or null to clear the current binding.
192     */
193    @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
194    public void setAndBindVrCompositor(ComponentName componentName) {
195        try {
196            mService.setAndBindCompositor(
197                    (componentName == null) ? null : componentName.flattenToString());
198        } catch (RemoteException e) {
199            e.rethrowFromSystemServer();
200        }
201    }
202
203    /**
204     * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
205     * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
206     *
207     * @param standby True if the device is entering standby, false if it's exiting standby.
208     * @hide
209     */
210    @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
211    public void setStandbyEnabled(boolean standby) {
212        try {
213            mService.setStandbyEnabled(standby);
214        } catch (RemoteException e) {
215            e.rethrowFromSystemServer();
216        }
217    }
218
219    /**
220     * Start VR Input method for the packageName in {@link ComponentName}.
221     * This method notifies InputMethodManagerService to use VR IME instead of
222     * regular phone IME.
223     * @param componentName ComponentName of a VR InputMethod that should be set as selected
224     * input by InputMethodManagerService.
225     * @hide
226     */
227    @TestApi
228    @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
229    public void setVrInputMethod(ComponentName componentName) {
230        try {
231            mService.setVrInputMethod(componentName);
232        } catch (RemoteException e) {
233            e.rethrowFromSystemServer();
234        }
235    }
236}
237