diff options
| author | 2017-08-08 17:11:41 -0700 | |
|---|---|---|
| committer | 2017-08-24 21:45:24 +0000 | |
| commit | e6d772330744d2c27545dabfe60a4023495c0925 (patch) | |
| tree | 85ad1bee9bddc8ad6f134f97e0ca1de697ba244c | |
| parent | ba893e6a1004f3d8fc40fb64ac43960a7446d0f7 (diff) | |
Allow VR State Listeners with RESTRICTED_VR_ACCESS permission.
Extend the ability to use VrStateListeners to applications that
have RESTRICTED_VR_ACCESS permission. Previously, it required
ACCESS_VR_MANAGER only.
Add VrStateCallback object and methods to VrManager to access the
functionality outside of frameworks.
Bug: 64360244
Test: Manual. Tested ability from VrCore.
Change-Id: I01f1c75b1ccd44a09364df84218168cf6caab322
| -rw-r--r-- | core/java/android/app/VrManager.java | 113 | ||||
| -rw-r--r-- | core/java/android/app/VrStateCallback.java | 38 | ||||
| -rw-r--r-- | core/java/android/service/vr/IVrManager.aidl | 7 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 5 | ||||
| -rw-r--r-- | services/core/java/com/android/server/vr/VrManagerService.java | 50 |
5 files changed, 201 insertions, 12 deletions
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java index b40c96c6f0c8..363e20a76a1f 100644 --- a/core/java/android/app/VrManager.java +++ b/core/java/android/app/VrManager.java @@ -1,13 +1,18 @@ package android.app; - +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.content.ComponentName; import android.content.Context; +import android.os.Handler; import android.os.RemoteException; +import android.service.vr.IPersistentVrStateCallbacks; import android.service.vr.IVrManager; +import android.service.vr.IVrStateCallbacks; +import android.util.ArrayMap; + +import java.util.Map; /** * Used to control aspects of a devices Virtual Reality (VR) capabilities. @@ -16,7 +21,33 @@ import android.service.vr.IVrManager; @SystemApi @SystemService(Context.VR_SERVICE) public class VrManager { + + private static class CallbackEntry { + final IVrStateCallbacks mStateCallback = new IVrStateCallbacks.Stub() { + @Override + public void onVrStateChanged(boolean enabled) { + mHandler.post(() -> mCallback.onVrStateChanged(enabled)); + } + + }; + final IPersistentVrStateCallbacks mPersistentStateCallback = + new IPersistentVrStateCallbacks.Stub() { + @Override + public void onPersistentVrStateChanged(boolean enabled) { + mHandler.post(() -> mCallback.onPersistentVrStateChanged(enabled)); + } + }; + final VrStateCallback mCallback; + final Handler mHandler; + + CallbackEntry(VrStateCallback callback, Handler handler) { + mCallback = callback; + mHandler = handler; + } + } + private final IVrManager mService; + private Map<VrStateCallback, CallbackEntry> mCallbackMap = new ArrayMap<>(); /** * {@hide} @@ -26,6 +57,84 @@ public class VrManager { } /** + * Registers a callback to be notified of changes to the VR Mode state. + * + * @param callback The callback to register. + * @hide + */ + @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) + public void registerVrStateCallback(VrStateCallback callback, @NonNull Handler handler) { + if (callback == null || mCallbackMap.containsKey(callback)) { + return; + } + + CallbackEntry entry = new CallbackEntry(callback, handler); + 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. + * @hide + */ + @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) + public void unregisterVrStateCallback(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. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_VR_STATE) + public boolean getVrModeEnabled() { + try { + return mService.getVrModeState(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return false; + } + + /** + * Returns the current VrMode state. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_VR_STATE) + public boolean getPersistentVrModeEnabled() { + 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. diff --git a/core/java/android/app/VrStateCallback.java b/core/java/android/app/VrStateCallback.java new file mode 100644 index 000000000000..742faa06fd1d --- /dev/null +++ b/core/java/android/app/VrStateCallback.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.app; + +/** + * Listens to VR Mode state changes. Use with methods in {@link VrManager}. + * + * @hide + */ +public abstract class VrStateCallback { + + /** + * Callback triggered when there is a change to Persistent VR State. + * + * @param enabled True when VR State is in persistent mode, false otherwise. + */ + public void onPersistentVrStateChanged(boolean enabled) {} + + /** + * Callback triggered when there is a change to Vr State. + * + * @param enabled True when VR State is in VR mode, false otherwise. + */ + public void onVrStateChanged(boolean enabled) {} +} diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl index 9b37a654ab98..c38fab1f9e2c 100644 --- a/core/java/android/service/vr/IVrManager.aidl +++ b/core/java/android/service/vr/IVrManager.aidl @@ -59,6 +59,13 @@ interface IVrManager { boolean getVrModeState(); /** + * Returns the current Persistent VR mode state. + * + * @return {@code true} if Persistent VR mode is enabled. + */ + boolean getPersistentVrModeEnabled(); + + /** * 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. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 86c0b436ae29..89bbec2b3bcc 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3512,6 +3512,11 @@ <permission android:name="android.permission.ACCESS_VR_MANAGER" android:protectionLevel="signature" /> + <!-- Required to access VR-Mode state and state change events via {android.app.VrStateCallback} + @hide --> + <permission android:name="android.permission.ACCESS_VR_STATE" + android:protectionLevel="signature|preinstalled" /> + <!-- Allows an application to whitelist tasks during lock task mode @hide <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index b6b964b050e3..1f0b2f000be1 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -74,6 +74,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.StringBuilder; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -414,7 +415,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void registerListener(IVrStateCallbacks cb) { - enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); if (cb == null) { throw new IllegalArgumentException("Callback binder object is null."); } @@ -424,7 +426,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void unregisterListener(IVrStateCallbacks cb) { - enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); if (cb == null) { throw new IllegalArgumentException("Callback binder object is null."); } @@ -434,7 +437,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void registerPersistentVrStateListener(IPersistentVrStateCallbacks cb) { - enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); if (cb == null) { throw new IllegalArgumentException("Callback binder object is null."); } @@ -444,7 +448,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void unregisterPersistentVrStateListener(IPersistentVrStateCallbacks cb) { - enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); if (cb == null) { throw new IllegalArgumentException("Callback binder object is null."); } @@ -454,19 +459,28 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public boolean getVrModeState() { + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); return VrManagerService.this.getVrMode(); } @Override + public boolean getPersistentVrModeEnabled() { + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER, + Manifest.permission.ACCESS_VR_STATE); + return VrManagerService.this.getPersistentVrMode(); + } + + @Override public void setPersistentVrModeEnabled(boolean enabled) { - enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS); + enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS); VrManagerService.this.setPersistentVrModeEnabled(enabled); } @Override public void setVr2dDisplayProperties( Vr2dDisplayProperties vr2dDisplayProp) { - enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS); + enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS); VrManagerService.this.setVr2dDisplayProperties(vr2dDisplayProp); } @@ -530,11 +544,21 @@ public class VrManagerService extends SystemService implements EnabledComponentC }; - private void enforceCallerPermission(String permission) { - if (mContext.checkCallingOrSelfPermission(permission) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Caller does not hold the permission " + permission); + /** + * Enforces that at lease one of the specified permissions is held by the caller. + * Throws SecurityException if none of the specified permissions are held. + * + * @param permissions One or more permissions to check against. + */ + private void enforceCallerPermissionAnyOf(String... permissions) { + for (String permission : permissions) { + if (mContext.checkCallingOrSelfPermission(permission) + == PackageManager.PERMISSION_GRANTED) { + return; + } } + throw new SecurityException("Caller does not hold at least one of the permissions: " + + Arrays.toString(permissions)); } /** @@ -1204,4 +1228,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC return mVrModeEnabled; } } + + private boolean getPersistentVrMode() { + synchronized (mLock) { + return mPersistentVrModeEnabled; + } + } } |