1 package android.app;
2 
3 import android.annotation.CallbackExecutor;
4 import android.annotation.NonNull;
5 import android.annotation.Nullable;
6 import android.annotation.RequiresPermission;
7 import android.annotation.SystemApi;
8 import android.annotation.SystemService;
9 import android.compat.annotation.UnsupportedAppUsage;
10 import android.content.ComponentName;
11 import android.content.Context;
12 import android.os.RemoteException;
13 import android.service.vr.IPersistentVrStateCallbacks;
14 import android.service.vr.IVrManager;
15 import android.service.vr.IVrStateCallbacks;
16 import android.util.ArrayMap;
17 import android.view.Display;
18 
19 import java.util.Map;
20 import java.util.concurrent.Executor;
21 
22 /**
23  * Used to control aspects of a devices Virtual Reality (VR) capabilities.
24  * @hide
25  */
26 @SystemApi
27 @SystemService(Context.VR_SERVICE)
28 public class VrManager {
29 
30     private static class CallbackEntry {
31         final IVrStateCallbacks mStateCallback = new IVrStateCallbacks.Stub() {
32             @Override
33             public void onVrStateChanged(boolean enabled) {
34                 mExecutor.execute(() -> mCallback.onVrStateChanged(enabled));
35             }
36 
37         };
38         final IPersistentVrStateCallbacks mPersistentStateCallback =
39                 new IPersistentVrStateCallbacks.Stub() {
40             @Override
41             public void onPersistentVrStateChanged(boolean enabled) {
42                 mExecutor.execute(() -> mCallback.onPersistentVrStateChanged(enabled));
43             }
44         };
45         final VrStateCallback mCallback;
46         final Executor mExecutor;
47 
CallbackEntry(VrStateCallback callback, Executor executor)48         CallbackEntry(VrStateCallback callback, Executor executor) {
49             mCallback = callback;
50             mExecutor = executor;
51         }
52     }
53 
54     @UnsupportedAppUsage
55     private final IVrManager mService;
56     private Map<VrStateCallback, CallbackEntry> mCallbackMap = new ArrayMap<>();
57 
58     /**
59      * {@hide}
60      */
VrManager(IVrManager service)61     public VrManager(IVrManager service) {
62         mService = service;
63     }
64 
65     /**
66      * Registers a callback to be notified of changes to the VR Mode state.
67      *
68      * @param callback The callback to register.
69      */
70     @RequiresPermission(anyOf = {
71             android.Manifest.permission.RESTRICTED_VR_ACCESS,
72             android.Manifest.permission.ACCESS_VR_STATE
73     })
registerVrStateCallback(@onNull @allbackExecutor Executor executor, @NonNull VrStateCallback callback)74     public void registerVrStateCallback(@NonNull @CallbackExecutor Executor executor,
75             @NonNull VrStateCallback callback) {
76         if (callback == null || mCallbackMap.containsKey(callback)) {
77             return;
78         }
79 
80         CallbackEntry entry = new CallbackEntry(callback, executor);
81         mCallbackMap.put(callback, entry);
82         try {
83             mService.registerListener(entry.mStateCallback);
84             mService.registerPersistentVrStateListener(entry.mPersistentStateCallback);
85         } catch (RemoteException e) {
86             try {
87                 unregisterVrStateCallback(callback);
88             } catch (Exception ignore) {
89                 e.rethrowFromSystemServer();
90             }
91         }
92     }
93 
94     /**
95      * Deregisters VR State callbacks.
96      *
97      * @param callback The callback to deregister.
98      */
99     @RequiresPermission(anyOf = {
100             android.Manifest.permission.RESTRICTED_VR_ACCESS,
101             android.Manifest.permission.ACCESS_VR_STATE
102     })
unregisterVrStateCallback(@onNull VrStateCallback callback)103     public void unregisterVrStateCallback(@NonNull VrStateCallback callback) {
104         CallbackEntry entry = mCallbackMap.remove(callback);
105         if (entry != null) {
106             try {
107                 mService.unregisterListener(entry.mStateCallback);
108             } catch (RemoteException ignore) {
109                 // Dont rethrow exceptions from requests to unregister.
110             }
111 
112             try {
113                 mService.unregisterPersistentVrStateListener(entry.mPersistentStateCallback);
114             } catch (RemoteException ignore) {
115                 // Dont rethrow exceptions from requests to unregister.
116             }
117         }
118     }
119 
120     /**
121      * Returns the current VrMode state.
122      */
123     @RequiresPermission(anyOf = {
124             android.Manifest.permission.RESTRICTED_VR_ACCESS,
125             android.Manifest.permission.ACCESS_VR_STATE
126     })
isVrModeEnabled()127     public boolean isVrModeEnabled() {
128         try {
129             return mService.getVrModeState();
130         } catch (RemoteException e) {
131             e.rethrowFromSystemServer();
132         }
133         return false;
134     }
135 
136     /**
137      * Returns the current VrMode state.
138      */
139     @RequiresPermission(anyOf = {
140             android.Manifest.permission.RESTRICTED_VR_ACCESS,
141             android.Manifest.permission.ACCESS_VR_STATE
142     })
isPersistentVrModeEnabled()143     public boolean isPersistentVrModeEnabled() {
144         try {
145             return mService.getPersistentVrModeEnabled();
146         } catch (RemoteException e) {
147             e.rethrowFromSystemServer();
148         }
149         return false;
150     }
151 
152     /**
153      * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
154      * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
155      * by VR viewers to indicate that a device is placed in a VR viewer.
156      *
157      * @see Activity#setVrModeEnabled(boolean, ComponentName)
158      * @param enabled true if the device should be placed in persistent VR mode.
159      */
160     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
setPersistentVrModeEnabled(boolean enabled)161     public void setPersistentVrModeEnabled(boolean enabled) {
162         try {
163             mService.setPersistentVrModeEnabled(enabled);
164         } catch (RemoteException e) {
165             e.rethrowFromSystemServer();
166         }
167     }
168 
169     /**
170      * Sets the resolution and DPI of the vr2d virtual display used to display 2D
171      * applications in VR mode.
172      *
173      * @param vr2dDisplayProp properties to be set to the virtual display for
174      * 2D applications in VR mode.
175      *
176      */
177     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
setVr2dDisplayProperties( @onNull Vr2dDisplayProperties vr2dDisplayProp)178     public void setVr2dDisplayProperties(
179             @NonNull 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)
setAndBindVrCompositor(ComponentName componentName)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      */
209     @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
setStandbyEnabled(boolean standby)210     public void setStandbyEnabled(boolean standby) {
211         try {
212             mService.setStandbyEnabled(standby);
213         } catch (RemoteException e) {
214             e.rethrowFromSystemServer();
215         }
216     }
217 
218     /**
219      * This method is not implemented.
220      *
221      * @param componentName not used
222      */
223     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
setVrInputMethod(@ullable ComponentName componentName)224     public void setVrInputMethod(@Nullable ComponentName componentName) {
225     }
226 
227     /**
228      * Returns the display id of VR's {@link VirtualDisplay}.
229      *
230      * @see DisplayManager#getDisplay(int)
231      */
232     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
getVr2dDisplayId()233     public int getVr2dDisplayId() {
234         try {
235             return mService.getVr2dDisplayId();
236         } catch (RemoteException e) {
237             e.rethrowFromSystemServer();
238         }
239         return Display.INVALID_DISPLAY;
240     }
241 }
242