Add VrManager AIDL interface for use by system apps.
Bug: 27884853
Change-Id: I6de0d291deafe5003070d60866c60d6599312e79
diff --git a/Android.mk b/Android.mk
index fc9c319..ae5d67e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -244,6 +244,8 @@
core/java/android/service/notification/IConditionListener.aidl \
core/java/android/service/notification/IConditionProvider.aidl \
core/java/android/service/vr/IVrListener.aidl \
+ core/java/android/service/vr/IVrManager.aidl \
+ core/java/android/service/vr/IVrStateCallbacks.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
new file mode 100644
index 0000000..62ecab3
--- /dev/null
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2016, 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.service.vr;
+
+import android.service.vr.IVrStateCallbacks;
+
+/** @hide */
+interface IVrManager {
+
+ /**
+ * Add a callback to be notified when VR mode state changes.
+ *
+ * @param cb the callback instance to add.
+ */
+ void registerListener(in IVrStateCallbacks cb);
+
+ /**
+ * Remove the callack from the current set of registered callbacks.
+ *
+ * @param cb the callback to remove.
+ */
+ void unregisterListener(in IVrStateCallbacks cb);
+
+ /**
+ * Return current VR mode state.
+ *
+ * @return {@code true} if VR mode is enabled.
+ */
+ boolean getVrModeState();
+
+}
+
diff --git a/core/java/android/service/vr/IVrStateCallbacks.aidl b/core/java/android/service/vr/IVrStateCallbacks.aidl
new file mode 100644
index 0000000..c4fdcd0
--- /dev/null
+++ b/core/java/android/service/vr/IVrStateCallbacks.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, 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.service.vr;
+
+/** @hide */
+oneway interface IVrStateCallbacks {
+
+ void onVrStateChanged(in boolean enabled);
+
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9219e81..af81585 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2991,6 +2991,11 @@
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Required to make calls to {@link android.service.vr.IVrManager}.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_VR_MANAGER"
+ android:protectionLevel="signature" />
+
<!-- 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/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 257c7da..5953dde 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -18,12 +18,17 @@
import com.android.server.SystemService;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrManagerService;
import com.android.server.vr.VrStateListener;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
+import android.os.RemoteException;
import android.os.Trace;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.Slog;
public class LightsService extends SystemService {
@@ -164,13 +169,19 @@
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
+ IVrManager vrManager =
+ (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
}
}
- private final VrStateListener mVrStateListener = new VrStateListener() {
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
- public void onVrStateChanged(boolean enabled) {
+ public void onVrStateChanged(boolean enabled) throws RemoteException {
LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
if (enabled) {
if (DEBUG) Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 7570960..8cd536d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -53,6 +53,8 @@
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -72,6 +74,7 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrManagerService;
import com.android.server.vr.VrStateListener;
import libcore.util.Objects;
@@ -658,7 +661,13 @@
resolver.registerContentObserver(Settings.Secure.getUriFor(
Secure.BRIGHTNESS_USE_TWILIGHT),
false, mSettingsObserver, UserHandle.USER_ALL);
- getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
+ IVrManager vrManager =
+ (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -3007,7 +3016,7 @@
}
}
- private final VrStateListener mVrStateListener = new VrStateListener() {
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
public void onVrStateChanged(boolean enabled) {
powerHintInternal(POWER_HINT_VR_MODE, enabled ? 1 : 0);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 93bb9d7..1bbb9f5 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -31,13 +31,6 @@
public static final int NO_ERROR = 0;
/**
- * Return current VR mode state.
- *
- * @return {@code true} if VR mode is enabled.
- */
- public abstract boolean isInVrMode();
-
- /**
* Return {@code true} if the given package is the currently bound VrListenerService for the
* given user.
*
@@ -59,22 +52,6 @@
public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
int userId, @NonNull ComponentName calling);
- /**
- * Add a listener for VR mode state changes.
- * <p>
- * This listener will immediately be called with the current VR mode state.
- * </p>
- * @param listener the listener instance to add.
- */
- public abstract void registerListener(@NonNull VrStateListener listener);
-
- /**
- * Remove the listener from the current set of listeners.
- *
- * @param listener the listener to remove.
- */
- public abstract void unregisterListener(@NonNull VrStateListener listener);
-
/**
* Return NO_ERROR if the given package is installed on the device and enabled as a
* VrListenerService for the given current user, or a negative error code indicating a failure.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index c572e76..e6e5a2d 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.vr;
+import android.Manifest;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
@@ -29,11 +30,15 @@
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.vr.IVrListener;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
import android.util.Slog;
@@ -46,6 +51,7 @@
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import java.lang.StringBuilder;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
@@ -75,6 +81,8 @@
public static final String TAG = "VrManagerService";
+ public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager";
+
private static native void initializeNative();
private static native void setVrModeNative(boolean enabled);
@@ -84,7 +92,6 @@
// State protected by mLock
private boolean mVrModeEnabled;
- private final Set<VrStateListener> mListeners = new ArraySet<>();
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private Context mContext;
@@ -92,10 +99,37 @@
private int mCurrentVrModeUser;
private boolean mWasDefaultGranted;
private boolean mGuard;
+ private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks =
+ new RemoteCallbackList<>();
private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
private String mPreviousNotificationPolicyAccessPackage;
private String mPreviousManageOverlayPackage;
+ private static final int MSG_VR_STATE_CHANGE = 0;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_VR_STATE_CHANGE : {
+ boolean state = (msg.arg1 == 1);
+ int i = mRemoteCallbacks.beginBroadcast();
+ while (i > 0) {
+ i--;
+ try {
+ mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state);
+ } catch (RemoteException e) {
+ // Noop
+ }
+ }
+ mRemoteCallbacks.finishBroadcast();
+ } break;
+ default :
+ throw new IllegalStateException("Unknown message type: " + msg.what);
+ }
+ }
+ };
+
private static final BinderChecker sBinderChecker = new BinderChecker() {
@Override
public IInterface asInterface(IBinder binder) {
@@ -125,16 +159,47 @@
}
}
+ private final IVrManager mVrManager = new IVrManager.Stub() {
+
+ @Override
+ public void registerListener(IVrStateCallbacks cb) {
+ enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback binder object is null.");
+ }
+
+ VrManagerService.this.addStateCallback(cb);
+ }
+
+ @Override
+ public void unregisterListener(IVrStateCallbacks cb) {
+ enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback binder object is null.");
+ }
+
+ VrManagerService.this.removeStateCallback(cb);
+ }
+
+ @Override
+ public boolean getVrModeState() {
+ return VrManagerService.this.getVrMode();
+ }
+
+ };
+
+ private void enforceCallerPermission(String permission) {
+ if (mContext.checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold the permission " + permission);
+ }
+ }
+
/**
* Implementation of VrManagerInternal. Callable only from system services.
*/
private final class LocalService extends VrManagerInternal {
@Override
- public boolean isInVrMode() {
- return VrManagerService.this.getVrMode();
- }
-
- @Override
public void setVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage) {
VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
@@ -146,16 +211,6 @@
}
@Override
- public void registerListener(VrStateListener listener) {
- VrManagerService.this.addListener(listener);
- }
-
- @Override
- public void unregisterListener(VrStateListener listener) {
- VrManagerService.this.removeListener(listener);
- }
-
- @Override
public int hasVrPackage(ComponentName packageName, int userId) {
return VrManagerService.this.hasVrPackage(packageName, userId);
}
@@ -173,6 +228,7 @@
}
publishLocalService(VrManagerInternal.class, new LocalService());
+ publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder());
}
@Override
@@ -551,9 +607,8 @@
* Note: Must be called while holding {@code mLock}.
*/
private void onVrModeChangedLocked() {
- for (VrStateListener l : mListeners) {
- l.onVrStateChanged(mVrModeEnabled);
- }
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_VR_STATE_CHANGE,
+ (mVrModeEnabled) ? 1 : 0, 0));
}
/**
@@ -577,9 +632,9 @@
}
}
- private boolean getVrMode() {
+ private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
synchronized (mLock) {
- return mVrModeEnabled;
+ return mComponentObserver.isValid(targetPackageName, userId);
}
}
@@ -593,21 +648,21 @@
}
}
- private void addListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.add(listener);
- }
+ /*
+ * Implementation of IVrManager calls.
+ */
+
+ private void addStateCallback(IVrStateCallbacks cb) {
+ mRemoteCallbacks.register(cb);
}
- private void removeListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.remove(listener);
- }
+ private void removeStateCallback(IVrStateCallbacks cb) {
+ mRemoteCallbacks.unregister(cb);
}
- private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
+ private boolean getVrMode() {
synchronized (mLock) {
- return mComponentObserver.isValid(targetPackageName, userId);
+ return mVrModeEnabled;
}
}
}