summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Santos Cordon <santoscordon@google.com> 2017-08-08 17:11:41 -0700
committer Santos Cordon <santoscordon@google.com> 2017-08-24 21:45:24 +0000
commite6d772330744d2c27545dabfe60a4023495c0925 (patch)
tree85ad1bee9bddc8ad6f134f97e0ca1de697ba244c
parentba893e6a1004f3d8fc40fb64ac43960a7446d0f7 (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.java113
-rw-r--r--core/java/android/app/VrStateCallback.java38
-rw-r--r--core/java/android/service/vr/IVrManager.aidl7
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java50
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;
+ }
+ }
}