diff --git a/Android.mk b/Android.mk index fc9c319a996ac..ae5d67ed2de3a 100644 --- a/Android.mk +++ b/Android.mk @@ -244,6 +244,8 @@ LOCAL_SRC_FILES += \ 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 0000000000000..62ecab3583cd2 --- /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 0000000000000..c4fdcd071fe5d --- /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 9219e81fb69b5..af8158556255b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2991,6 +2991,11 @@ + + + - * This listener will immediately be called with the current VR mode state. - *

- * @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 c572e766f1ec1..e6e5a2db0725f 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.Handler; 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; 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 class VrManagerService extends SystemService implements EnabledComponentC 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 @@ public class VrManagerService extends SystemService implements EnabledComponentC // State protected by mLock private boolean mVrModeEnabled; - private final Set mListeners = new ArraySet<>(); private EnabledComponentsObserver mComponentObserver; private ManagedApplicationService mCurrentVrService; private Context mContext; @@ -92,10 +99,37 @@ public class VrManagerService extends SystemService implements EnabledComponentC private int mCurrentVrModeUser; private boolean mWasDefaultGranted; private boolean mGuard; + private final RemoteCallbackList mRemoteCallbacks = + new RemoteCallbackList<>(); private final ArraySet 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,15 +159,46 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } + 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) { @@ -145,16 +210,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC return VrManagerService.this.isCurrentVrListener(packageName, userId); } - @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 @@ public class VrManagerService extends SystemService implements EnabledComponentC } publishLocalService(VrManagerInternal.class, new LocalService()); + publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder()); } @Override @@ -551,9 +607,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC * 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 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } - private boolean getVrMode() { + private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) { synchronized (mLock) { - return mVrModeEnabled; + return mComponentObserver.isValid(targetPackageName, userId); } } @@ -593,21 +648,21 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } - 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; } } }