package android.app; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.service.vr.IPersistentVrStateCallbacks; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.util.ArrayMap; import android.view.Display; import java.util.Map; import java.util.concurrent.Executor; /** * Used to control aspects of a devices Virtual Reality (VR) capabilities. * @hide */ @SystemApi @SystemService(Context.VR_SERVICE) public class VrManager { private static class CallbackEntry { final IVrStateCallbacks mStateCallback = new IVrStateCallbacks.Stub() { @Override public void onVrStateChanged(boolean enabled) { mExecutor.execute(() -> mCallback.onVrStateChanged(enabled)); } }; final IPersistentVrStateCallbacks mPersistentStateCallback = new IPersistentVrStateCallbacks.Stub() { @Override public void onPersistentVrStateChanged(boolean enabled) { mExecutor.execute(() -> mCallback.onPersistentVrStateChanged(enabled)); } }; final VrStateCallback mCallback; final Executor mExecutor; CallbackEntry(VrStateCallback callback, Executor executor) { mCallback = callback; mExecutor = executor; } } @UnsupportedAppUsage private final IVrManager mService; private Map mCallbackMap = new ArrayMap<>(); /** * {@hide} */ public VrManager(IVrManager service) { mService = service; } /** * Registers a callback to be notified of changes to the VR Mode state. * * @param callback The callback to register. */ @RequiresPermission(anyOf = { android.Manifest.permission.RESTRICTED_VR_ACCESS, android.Manifest.permission.ACCESS_VR_STATE }) public void registerVrStateCallback(@NonNull @CallbackExecutor Executor executor, @NonNull VrStateCallback callback) { if (callback == null || mCallbackMap.containsKey(callback)) { return; } CallbackEntry entry = new CallbackEntry(callback, executor); mCallbackMap.put(callback, entry); try { mService.registerListener(entry.mStateCallback); mService.registerPersistentVrStateListener(entry.mPersistentStateCallback); } catch (RemoteException e) { try { unregisterVrStateCallback(callback); } catch (Exception ignore) { e.rethrowFromSystemServer(); } } } /** * Deregisters VR State callbacks. * * @param callback The callback to deregister. */ @RequiresPermission(anyOf = { android.Manifest.permission.RESTRICTED_VR_ACCESS, android.Manifest.permission.ACCESS_VR_STATE }) public void unregisterVrStateCallback(@NonNull VrStateCallback callback) { CallbackEntry entry = mCallbackMap.remove(callback); if (entry != null) { try { mService.unregisterListener(entry.mStateCallback); } catch (RemoteException ignore) { // Dont rethrow exceptions from requests to unregister. } try { mService.unregisterPersistentVrStateListener(entry.mPersistentStateCallback); } catch (RemoteException ignore) { // Dont rethrow exceptions from requests to unregister. } } } /** * Returns the current VrMode state. */ @RequiresPermission(anyOf = { android.Manifest.permission.RESTRICTED_VR_ACCESS, android.Manifest.permission.ACCESS_VR_STATE }) public boolean isVrModeEnabled() { try { return mService.getVrModeState(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return false; } /** * Returns the current VrMode state. */ @RequiresPermission(anyOf = { android.Manifest.permission.RESTRICTED_VR_ACCESS, android.Manifest.permission.ACCESS_VR_STATE }) public boolean isPersistentVrModeEnabled() { try { return mService.getPersistentVrModeEnabled(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return false; } /** * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used * by VR viewers to indicate that a device is placed in a VR viewer. * * @see Activity#setVrModeEnabled(boolean, ComponentName) * @param enabled true if the device should be placed in persistent VR mode. */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setPersistentVrModeEnabled(boolean enabled) { try { mService.setPersistentVrModeEnabled(enabled); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Sets the resolution and DPI of the vr2d virtual display used to display 2D * applications in VR mode. * * @param vr2dDisplayProp properties to be set to the virtual display for * 2D applications in VR mode. * */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties( @NonNull Vr2dDisplayProperties vr2dDisplayProp) { try { mService.setVr2dDisplayProperties(vr2dDisplayProp); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Set the component name of the compositor service to bind. * * @param componentName ComponentName of a Service in the application's compositor process to * bind to, or null to clear the current binding. */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setAndBindVrCompositor(ComponentName componentName) { try { mService.setAndBindCompositor( (componentName == null) ? null : componentName.flattenToString()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Sets the current standby status of the VR device. Standby mode is only used on standalone vr * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode. * * @param standby True if the device is entering standby, false if it's exiting standby. */ @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER) public void setStandbyEnabled(boolean standby) { try { mService.setStandbyEnabled(standby); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * This method is not implemented. * * @param componentName not used */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(@Nullable ComponentName componentName) { } /** * Returns the display id of VR's {@link VirtualDisplay}. * * @see DisplayManager#getDisplay(int) */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public int getVr2dDisplayId() { try { return mService.getVr2dDisplayId(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } return Display.INVALID_DISPLAY; } }