2 * Copyright (C) 2015 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.android.server.vr;
18 import android.Manifest;
19 import android.app.ActivityManager;
20 import android.app.AppOpsManager;
21 import android.app.NotificationManager;
22 import android.annotation.NonNull;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.ApplicationInfo;
30 import android.content.pm.FeatureInfo;
31 import android.content.pm.PackageInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.PackageManager.NameNotFoundException;
34 import android.os.Binder;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.IInterface;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.os.RemoteCallbackList;
41 import android.os.RemoteException;
42 import android.os.UserHandle;
43 import android.provider.Settings;
44 import android.service.notification.NotificationListenerService;
45 import android.service.vr.IVrListener;
46 import android.service.vr.IVrManager;
47 import android.service.vr.IVrStateCallbacks;
48 import android.service.vr.VrListenerService;
49 import android.text.TextUtils;
50 import android.util.ArrayMap;
51 import android.util.ArraySet;
52 import android.util.Slog;
53 import android.util.SparseArray;
54 import com.android.internal.R;
55 import com.android.server.LocalServices;
56 import com.android.server.SystemConfig;
57 import com.android.server.SystemService;
58 import com.android.server.utils.ManagedApplicationService.PendingEvent;
59 import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
60 import com.android.server.utils.ManagedApplicationService;
61 import com.android.server.utils.ManagedApplicationService.BinderChecker;
63 import java.io.FileDescriptor;
64 import java.io.PrintWriter;
65 import java.lang.StringBuilder;
66 import java.text.SimpleDateFormat;
67 import java.util.ArrayDeque;
68 import java.util.ArrayList;
69 import java.util.Collection;
70 import java.util.Date;
71 import java.util.List;
73 import java.util.Objects;
76 * Service tracking whether VR mode is active, and notifying listening services of state changes.
78 * Services running in system server may modify the state of VrManagerService via the interface in
79 * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the
80 * interface given in VrStateListener.
82 * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.:
83 * hardware/libhardware/modules/vr
85 * In general applications may enable or disable VR mode by calling
86 * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to
87 * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
89 * @see android.service.vr.VrListenerService
90 * @see com.android.server.vr.VrManagerInternal
91 * @see com.android.server.vr.VrStateListener
95 public class VrManagerService extends SystemService implements EnabledComponentChangeListener{
97 public static final String TAG = "VrManagerService";
99 public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager";
101 private static final int PENDING_STATE_DELAY_MS = 300;
102 private static final int EVENT_LOG_SIZE = 32;
103 private static final int INVALID_APPOPS_MODE = -1;
105 private static native void initializeNative();
106 private static native void setVrModeNative(boolean enabled);
108 private final Object mLock = new Object();
110 private final IBinder mOverlayToken = new Binder();
112 // State protected by mLock
113 private boolean mVrModeEnabled;
114 private EnabledComponentsObserver mComponentObserver;
115 private ManagedApplicationService mCurrentVrService;
116 private Context mContext;
117 private ComponentName mCurrentVrModeComponent;
118 private int mCurrentVrModeUser;
119 private boolean mWasDefaultGranted;
120 private boolean mGuard;
121 private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks =
122 new RemoteCallbackList<>();
123 private int mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
124 private int mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
125 private VrState mPendingState;
126 private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
127 private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
129 private static final int MSG_VR_STATE_CHANGE = 0;
130 private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
132 private final Handler mHandler = new Handler() {
134 public void handleMessage(Message msg) {
136 case MSG_VR_STATE_CHANGE : {
137 boolean state = (msg.arg1 == 1);
138 int i = mRemoteCallbacks.beginBroadcast();
142 mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state);
143 } catch (RemoteException e) {
147 mRemoteCallbacks.finishBroadcast();
149 case MSG_PENDING_VR_STATE_CHANGE : {
150 synchronized(mLock) {
151 VrManagerService.this.consumeAndApplyPendingStateLocked();
155 throw new IllegalStateException("Unknown message type: " + msg.what);
160 private static class VrState {
161 final boolean enabled;
163 final ComponentName targetPackageName;
164 final ComponentName callingPackage;
165 final long timestamp;
166 final boolean defaultPermissionsGranted;
168 VrState(boolean enabled, ComponentName targetPackageName, int userId,
169 ComponentName callingPackage) {
170 this.enabled = enabled;
171 this.userId = userId;
172 this.targetPackageName = targetPackageName;
173 this.callingPackage = callingPackage;
174 this.defaultPermissionsGranted = false;
175 this.timestamp = System.currentTimeMillis();
178 VrState(boolean enabled, ComponentName targetPackageName, int userId,
179 ComponentName callingPackage, boolean defaultPermissionsGranted) {
180 this.enabled = enabled;
181 this.userId = userId;
182 this.targetPackageName = targetPackageName;
183 this.callingPackage = callingPackage;
184 this.defaultPermissionsGranted = defaultPermissionsGranted;
185 this.timestamp = System.currentTimeMillis();
189 private static final BinderChecker sBinderChecker = new BinderChecker() {
191 public IInterface asInterface(IBinder binder) {
192 return IVrListener.Stub.asInterface(binder);
196 public boolean checkType(IInterface service) {
197 return service instanceof IVrListener;
201 private final class NotificationAccessManager {
202 private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>();
203 private final ArrayMap<String, Integer> mNotificationAccessPackageToUserId =
206 public void update(Collection<String> packageNames) {
207 int currentUserId = ActivityManager.getCurrentUser();
209 ArraySet<String> allowed = mAllowedPackages.get(currentUserId);
210 if (allowed == null) {
211 allowed = new ArraySet<>();
214 // Make sure we revoke notification access for listeners in other users
215 final int listenerCount = mNotificationAccessPackageToUserId.size();
216 for (int i = listenerCount - 1; i >= 0; i--) {
217 final int grantUserId = mNotificationAccessPackageToUserId.valueAt(i);
218 if (grantUserId != currentUserId) {
219 String packageName = mNotificationAccessPackageToUserId.keyAt(i);
220 revokeNotificationListenerAccess(packageName, grantUserId);
221 revokeNotificationPolicyAccess(packageName);
222 revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
223 mNotificationAccessPackageToUserId.removeAt(i);
227 for (String pkg : allowed) {
228 if (!packageNames.contains(pkg)) {
229 revokeNotificationListenerAccess(pkg, currentUserId);
230 revokeNotificationPolicyAccess(pkg);
231 revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
232 mNotificationAccessPackageToUserId.remove(pkg);
235 for (String pkg : packageNames) {
236 if (!allowed.contains(pkg)) {
237 grantNotificationPolicyAccess(pkg);
238 grantNotificationListenerAccess(pkg, currentUserId);
239 grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
240 mNotificationAccessPackageToUserId.put(pkg, currentUserId);
245 allowed.addAll(packageNames);
246 mAllowedPackages.put(currentUserId, allowed);
251 * Called when a user, package, or setting changes that could affect whether or not the
252 * currently bound VrListenerService is changed.
255 public void onEnabledComponentChanged() {
256 synchronized (mLock) {
257 int currentUser = ActivityManager.getCurrentUser();
260 ArraySet<ComponentName> enabledListeners = mComponentObserver.getEnabled(currentUser);
262 ArraySet<String> enabledPackages = new ArraySet<>();
263 for (ComponentName n : enabledListeners) {
264 String pkg = n.getPackageName();
265 if (isDefaultAllowed(pkg)) {
266 enabledPackages.add(n.getPackageName());
269 mNotifAccessManager.update(enabledPackages);
271 if (mCurrentVrService == null) {
272 return; // No active services
275 // If there is a pending state change, we'd better deal with that first
276 consumeAndApplyPendingStateLocked();
278 if (mCurrentVrService == null) {
279 return; // No active services
282 // There is an active service, update it if needed
283 updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
284 mCurrentVrService.getUserId(), null);
288 private final IVrManager mVrManager = new IVrManager.Stub() {
291 public void registerListener(IVrStateCallbacks cb) {
292 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
294 throw new IllegalArgumentException("Callback binder object is null.");
297 VrManagerService.this.addStateCallback(cb);
301 public void unregisterListener(IVrStateCallbacks cb) {
302 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
304 throw new IllegalArgumentException("Callback binder object is null.");
307 VrManagerService.this.removeStateCallback(cb);
311 public boolean getVrModeState() {
312 return VrManagerService.this.getVrMode();
316 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
317 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
318 != PackageManager.PERMISSION_GRANTED) {
319 pw.println("permission denied: can't dump VrManagerService from pid="
320 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
323 pw.println("********* Dump of VrManagerService *********");
324 pw.println("Previous state transitions:\n");
326 dumpStateTransitions(pw);
327 pw.println("\n\nRemote Callbacks:");
328 int i=mRemoteCallbacks.beginBroadcast(); // create the broadcast item array
331 pw.print(mRemoteCallbacks.getBroadcastItem(i));
332 if (i>0) pw.println(",");
334 mRemoteCallbacks.finishBroadcast();
336 pw.println("Installed VrListenerService components:");
337 int userId = mCurrentVrModeUser;
338 ArraySet<ComponentName> installed = mComponentObserver.getInstalled(userId);
339 if (installed == null || installed.size() == 0) {
342 for (ComponentName n : installed) {
344 pw.println(n.flattenToString());
347 pw.println("Enabled VrListenerService components:");
348 ArraySet<ComponentName> enabled = mComponentObserver.getEnabled(userId);
349 if (enabled == null || enabled.size() == 0) {
352 for (ComponentName n : enabled) {
354 pw.println(n.flattenToString());
358 pw.println("********* End of VrManagerService Dump *********");
363 private void enforceCallerPermission(String permission) {
364 if (mContext.checkCallingOrSelfPermission(permission)
365 != PackageManager.PERMISSION_GRANTED) {
366 throw new SecurityException("Caller does not hold the permission " + permission);
371 * Implementation of VrManagerInternal. Callable only from system services.
373 private final class LocalService extends VrManagerInternal {
375 public void setVrMode(boolean enabled, ComponentName packageName, int userId,
376 ComponentName callingPackage) {
377 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false);
381 public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId,
382 ComponentName callingPackage) {
383 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true);
387 public boolean isCurrentVrListener(String packageName, int userId) {
388 return VrManagerService.this.isCurrentVrListener(packageName, userId);
392 public int hasVrPackage(ComponentName packageName, int userId) {
393 return VrManagerService.this.hasVrPackage(packageName, userId);
397 public VrManagerService(Context context) {
402 public void onStart() {
403 synchronized(mLock) {
405 mContext = getContext();
408 publishLocalService(VrManagerInternal.class, new LocalService());
409 publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder());
413 public void onBootPhase(int phase) {
414 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
415 synchronized (mLock) {
416 Looper looper = Looper.getMainLooper();
417 Handler handler = new Handler(looper);
418 ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>();
420 mComponentObserver = EnabledComponentsObserver.build(mContext, handler,
421 Settings.Secure.ENABLED_VR_LISTENERS, looper,
422 android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
423 VrListenerService.SERVICE_INTERFACE, mLock, listeners);
425 mComponentObserver.rebuildAll();
431 public void onStartUser(int userHandle) {
432 synchronized (mLock) {
433 mComponentObserver.onUsersChanged();
438 public void onSwitchUser(int userHandle) {
439 synchronized (mLock) {
440 mComponentObserver.onUsersChanged();
446 public void onStopUser(int userHandle) {
447 synchronized (mLock) {
448 mComponentObserver.onUsersChanged();
454 public void onCleanupUser(int userHandle) {
455 synchronized (mLock) {
456 mComponentObserver.onUsersChanged();
460 private void updateOverlayStateLocked(String exemptedPackage, int newUserId, int oldUserId) {
461 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
463 // If user changed drop restrictions for the old user.
464 if (oldUserId != newUserId) {
465 appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
466 false, mOverlayToken, null, oldUserId);
469 // Apply the restrictions for the current user based on vr state
470 String[] exemptions = (exemptedPackage == null) ? new String[0] :
471 new String[] { exemptedPackage };
473 appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
474 mVrModeEnabled, mOverlayToken, exemptions, newUserId);
477 private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
478 String oldVrServicePackage, int oldUserId) {
479 // If VR state changed and we also have a VR service change.
480 if (Objects.equals(newVrServicePackage, oldVrServicePackage)) {
483 final long identity = Binder.clearCallingIdentity();
485 // Set overlay exception state based on VR enabled and current service
486 updateOverlayStateLocked(newVrServicePackage, newUserId, oldUserId);
488 Binder.restoreCallingIdentity(identity);
493 * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of
494 * the currently selected VR listener service. If the component selected for the VR listener
495 * service has changed, unbind the previous listener and bind the new listener (if enabled).
497 * Note: Must be called while holding {@code mLock}.
499 * @param enabled new state for VR mode.
500 * @param component new component to be bound as a VR listener.
501 * @param userId user owning the component to be bound.
502 * @param calling the component currently using VR mode, or null to leave unchanged.
504 * @return {@code true} if the component/user combination specified is valid.
506 private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
507 int userId, ComponentName calling) {
509 boolean sendUpdatedCaller = false;
510 final long identity = Binder.clearCallingIdentity();
513 boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
514 EnabledComponentsObserver.NO_ERROR);
515 if (!mVrModeEnabled && !enabled) {
516 return validUserComponent; // Disabled -> Disabled transition does nothing.
519 String oldVrServicePackage = mCurrentVrService != null
520 ? mCurrentVrService.getComponent().getPackageName() : null;
521 final int oldUserId = mCurrentVrModeUser;
523 // Always send mode change events.
524 changeVrModeLocked(enabled);
526 if (!enabled || !validUserComponent) {
527 // Unbind whatever is running
528 if (mCurrentVrService != null) {
529 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
530 mCurrentVrService.getUserId());
531 mCurrentVrService.disconnect();
532 mCurrentVrService = null;
535 if (mCurrentVrService != null) {
536 // Unbind any running service that doesn't match the component/user selection
537 if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
538 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
539 " for user " + mCurrentVrService.getUserId());
540 createAndConnectService(component, userId);
541 sendUpdatedCaller = true;
543 // The service with the correct component/user is bound
545 // Nothing was previously running, bind a new service
546 createAndConnectService(component, userId);
547 sendUpdatedCaller = true;
551 if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
552 mCurrentVrModeComponent = calling;
553 sendUpdatedCaller = true;
556 if (mCurrentVrModeUser != userId) {
557 mCurrentVrModeUser = userId;
558 sendUpdatedCaller = true;
561 String newVrServicePackage = mCurrentVrService != null
562 ? mCurrentVrService.getComponent().getPackageName() : null;
563 final int newUserId = mCurrentVrModeUser;
565 // Update AppOps settings that change state when entering/exiting VR mode, or changing
566 // the current VrListenerService.
567 updateDependentAppOpsLocked(newVrServicePackage, newUserId,
568 oldVrServicePackage, oldUserId);
570 if (mCurrentVrService != null && sendUpdatedCaller) {
571 final ComponentName c = mCurrentVrModeComponent;
572 mCurrentVrService.sendEvent(new PendingEvent() {
574 public void runEvent(IInterface service) throws RemoteException {
575 IVrListener l = (IVrListener) service;
576 l.focusedActivityChanged(c);
582 return validUserComponent;
584 Binder.restoreCallingIdentity(identity);
588 private boolean isDefaultAllowed(String packageName) {
589 PackageManager pm = mContext.getPackageManager();
591 ApplicationInfo info = null;
593 info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
594 } catch (NameNotFoundException e) {
597 if (info == null || !(info.isSystemApp() || info.isUpdatedSystemApp())) {
603 private void grantNotificationPolicyAccess(String pkg) {
604 NotificationManager nm = mContext.getSystemService(NotificationManager.class);
605 nm.setNotificationPolicyAccessGranted(pkg, true);
608 private void revokeNotificationPolicyAccess(String pkg) {
609 NotificationManager nm = mContext.getSystemService(NotificationManager.class);
610 // Remove any DND zen rules possibly created by the package.
611 nm.removeAutomaticZenRules(pkg);
612 // Remove Notification Policy Access.
613 nm.setNotificationPolicyAccessGranted(pkg, false);
616 private void grantNotificationListenerAccess(String pkg, int userId) {
617 PackageManager pm = mContext.getPackageManager();
618 ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
619 userId, NotificationListenerService.SERVICE_INTERFACE,
620 android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
621 ContentResolver resolver = mContext.getContentResolver();
623 ArraySet<String> current = getNotificationListeners(resolver, userId);
625 for (ComponentName c : possibleServices) {
626 String flatName = c.flattenToString();
627 if (Objects.equals(c.getPackageName(), pkg)
628 && !current.contains(flatName)) {
629 current.add(flatName);
633 if (current.size() > 0) {
634 String flatSettings = formatSettings(current);
635 Settings.Secure.putStringForUser(resolver,
636 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
637 flatSettings, userId);
641 private void revokeNotificationListenerAccess(String pkg, int userId) {
642 ContentResolver resolver = mContext.getContentResolver();
644 ArraySet<String> current = getNotificationListeners(resolver, userId);
646 ArrayList<String> toRemove = new ArrayList<>();
648 for (String c : current) {
649 ComponentName component = ComponentName.unflattenFromString(c);
650 if (component != null && component.getPackageName().equals(pkg)) {
655 current.removeAll(toRemove);
657 String flatSettings = formatSettings(current);
658 Settings.Secure.putStringForUser(resolver,
659 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
660 flatSettings, userId);
663 private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
664 // Don't clobber the user if permission set in current state explicitly
665 if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
666 mContext.getPackageManager().grantRuntimePermission(pkg,
667 Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
671 private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
672 // Don't clobber the user if permission set in current state explicitly
673 if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
674 mContext.getPackageManager().revokeRuntimePermission(pkg,
675 Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
679 private boolean isPermissionUserUpdated(String permission, String pkg, int userId) {
680 final int flags = mContext.getPackageManager().getPermissionFlags(
681 permission, pkg, new UserHandle(userId));
682 return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
683 | PackageManager.FLAG_PERMISSION_USER_FIXED)) != 0;
686 private ArraySet<String> getNotificationListeners(ContentResolver resolver, int userId) {
687 String flat = Settings.Secure.getStringForUser(resolver,
688 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, userId);
690 ArraySet<String> current = new ArraySet<>();
692 String[] allowed = flat.split(":");
693 for (String s : allowed) {
694 if (!TextUtils.isEmpty(s)) {
702 private static String formatSettings(Collection<String> c) {
703 if (c == null || c.isEmpty()) {
707 StringBuilder b = new StringBuilder();
708 boolean start = true;
724 private void createAndConnectService(@NonNull ComponentName component, int userId) {
725 mCurrentVrService = VrManagerService.create(mContext, component, userId);
726 mCurrentVrService.connect();
727 Slog.i(TAG, "Connecting " + component + " for user " + userId);
731 * Send VR mode change callbacks to HAL and system services if mode has actually changed.
733 * Note: Must be called while holding {@code mLock}.
735 * @param enabled new state of the VR mode.
737 private void changeVrModeLocked(boolean enabled) {
738 if (mVrModeEnabled != enabled) {
739 mVrModeEnabled = enabled;
741 // Log mode change event.
742 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
743 setVrModeNative(mVrModeEnabled);
745 onVrModeChangedLocked();
750 * Notify system services of VR mode change.
752 * Note: Must be called while holding {@code mLock}.
754 private void onVrModeChangedLocked() {
755 mHandler.sendMessage(mHandler.obtainMessage(MSG_VR_STATE_CHANGE,
756 (mVrModeEnabled) ? 1 : 0, 0));
760 * Helper function for making ManagedApplicationService instances.
762 private static ManagedApplicationService create(@NonNull Context context,
763 @NonNull ComponentName component, int userId) {
764 return ManagedApplicationService.build(context, component, userId,
765 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
769 private void consumeAndApplyPendingStateLocked() {
770 if (mPendingState != null) {
771 updateCurrentVrServiceLocked(mPendingState.enabled,
772 mPendingState.targetPackageName, mPendingState.userId,
773 mPendingState.callingPackage);
774 mPendingState = null;
778 private void logStateLocked() {
779 ComponentName currentBoundService = (mCurrentVrService == null) ? null :
780 mCurrentVrService.getComponent();
781 VrState current = new VrState(mVrModeEnabled, currentBoundService, mCurrentVrModeUser,
782 mCurrentVrModeComponent, mWasDefaultGranted);
783 if (mLoggingDeque.size() == EVENT_LOG_SIZE) {
784 mLoggingDeque.removeFirst();
786 mLoggingDeque.add(current);
789 private void dumpStateTransitions(PrintWriter pw) {
790 SimpleDateFormat d = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
792 if (mLoggingDeque.size() == 0) {
796 for (VrState state : mLoggingDeque) {
797 pw.print(d.format(new Date(state.timestamp)));
799 pw.print("State changed to:");
801 pw.println((state.enabled) ? "ENABLED" : "DISABLED");
805 pw.println(state.userId);
807 pw.print("Current VR Activity=");
808 pw.println((state.callingPackage == null) ?
809 "None" : state.callingPackage.flattenToString());
811 pw.print("Bound VrListenerService=");
812 pw.println((state.targetPackageName == null) ?
813 "None" : state.targetPackageName.flattenToString());
814 if (state.defaultPermissionsGranted) {
816 pw.println("Default permissions granted to the bound VrListenerService.");
823 * Implementation of VrManagerInternal calls. These are callable from system services.
826 private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
827 int userId, @NonNull ComponentName callingPackage, boolean immediate) {
829 synchronized (mLock) {
831 if (!enabled && mCurrentVrService != null && !immediate) {
832 // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
833 // and service bind/unbind in case we are immediately switching to another VR app.
834 if (mPendingState == null) {
835 mHandler.sendEmptyMessageDelayed(MSG_PENDING_VR_STATE_CHANGE,
836 PENDING_STATE_DELAY_MS);
839 mPendingState = new VrState(enabled, targetPackageName, userId, callingPackage);
842 mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE);
843 mPendingState = null;
846 updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
850 private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
851 synchronized (mLock) {
852 return mComponentObserver.isValid(targetPackageName, userId);
856 private boolean isCurrentVrListener(String packageName, int userId) {
857 synchronized (mLock) {
858 if (mCurrentVrService == null) {
861 return mCurrentVrService.getComponent().getPackageName().equals(packageName) &&
862 userId == mCurrentVrService.getUserId();
867 * Implementation of IVrManager calls.
870 private void addStateCallback(IVrStateCallbacks cb) {
871 mRemoteCallbacks.register(cb);
874 private void removeStateCallback(IVrStateCallbacks cb) {
875 mRemoteCallbacks.unregister(cb);
878 private boolean getVrMode() {
879 synchronized (mLock) {
880 return mVrModeEnabled;