OSDN Git Service

Fix re-enabling alert window appop after leaving VR mode.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / vr / VrManagerService.java
index fdadc8d..14fe0e8 100644 (file)
@@ -86,9 +86,9 @@ import java.util.Objects;
  * {@link android.app.Activity#setVrModeEnabled)}.  An application may also implement a service to
  * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
  *
- * @see {@link android.service.vr.VrListenerService}
- * @see {@link com.android.server.vr.VrManagerInternal}
- * @see {@link com.android.server.vr.VrStateListener}
+ * @see android.service.vr.VrListenerService
+ * @see com.android.server.vr.VrManagerInternal
+ * @see com.android.server.vr.VrStateListener
  *
  * @hide
  */
@@ -101,6 +101,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     private static final int PENDING_STATE_DELAY_MS = 300;
     private static final int EVENT_LOG_SIZE = 32;
     private static final int INVALID_APPOPS_MODE = -1;
+    /** Null set of sleep sleep flags. */
+    private static final int FLAG_NONE = 0;
+    /** Flag set when the device is not sleeping. */
+    private static final int FLAG_AWAKE = 1;
+    /** Flag set when the screen has been turned on. */
+    private static final int FLAG_SCREEN_ON = 2;
+    /** Flag indicating that all system sleep flags have been set.*/
+    private static final int FLAG_ALL = FLAG_AWAKE | FLAG_SCREEN_ON;
 
     private static native void initializeNative();
     private static native void setVrModeNative(boolean enabled);
@@ -110,6 +118,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     private final IBinder mOverlayToken = new Binder();
 
     // State protected by mLock
+    private boolean mVrModeAllowed;
     private boolean mVrModeEnabled;
     private EnabledComponentsObserver mComponentObserver;
     private ManagedApplicationService mCurrentVrService;
@@ -125,10 +134,64 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     private VrState mPendingState;
     private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
     private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
+    /** Tracks the state of the screen and keyguard UI.*/
+    private int mSystemSleepFlags = FLAG_NONE;
 
     private static final int MSG_VR_STATE_CHANGE = 0;
     private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
 
+    /**
+     * Set whether VR mode may be enabled.
+     * <p/>
+     * If VR mode is not allowed to be enabled, calls to set VR mode will be cached.  When VR mode
+     * is again allowed to be enabled, the most recent cached state will be applied.
+     *
+     * @param allowed {@code true} if calling any of the setVrMode methods may cause the device to
+     *   enter VR mode.
+     */
+    private void setVrModeAllowedLocked(boolean allowed) {
+        if (mVrModeAllowed != allowed) {
+            mVrModeAllowed = allowed;
+            Slog.i(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
+            if (mVrModeAllowed) {
+                consumeAndApplyPendingStateLocked();
+            } else {
+                // Set pending state to current state.
+                mPendingState = (mVrModeEnabled && mCurrentVrService != null)
+                    ? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
+                        mCurrentVrService.getUserId(), mCurrentVrModeComponent)
+                    : null;
+
+                // Unbind current VR service and do necessary callbacks.
+                updateCurrentVrServiceLocked(false, null, 0, null);
+            }
+        }
+    }
+
+    private void setSleepState(boolean isAsleep) {
+        synchronized(mLock) {
+
+            if (!isAsleep) {
+                mSystemSleepFlags |= FLAG_AWAKE;
+            } else {
+                mSystemSleepFlags &= ~FLAG_AWAKE;
+            }
+
+            setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
+        }
+    }
+
+    private void setScreenOn(boolean isScreenOn) {
+        synchronized(mLock) {
+            if (isScreenOn) {
+                mSystemSleepFlags |= FLAG_SCREEN_ON;
+            } else {
+                mSystemSleepFlags &= ~FLAG_SCREEN_ON;
+            }
+            setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -148,7 +211,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                 } break;
                 case MSG_PENDING_VR_STATE_CHANGE : {
                     synchronized(mLock) {
-                        VrManagerService.this.consumeAndApplyPendingStateLocked();
+                        if (mVrModeAllowed) {
+                           VrManagerService.this.consumeAndApplyPendingStateLocked();
+                        }
                     }
                 } break;
                 default :
@@ -255,7 +320,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     public void onEnabledComponentChanged() {
         synchronized (mLock) {
             int currentUser = ActivityManager.getCurrentUser();
-
             // Update listeners
             ArraySet<ComponentName> enabledListeners = mComponentObserver.getEnabled(currentUser);
 
@@ -268,12 +332,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
             }
             mNotifAccessManager.update(enabledPackages);
 
-            if (mCurrentVrService == null) {
-                return; // No active services
+            if (!mVrModeAllowed) {
+                return; // Don't do anything, we shouldn't be in VR mode.
             }
 
             // If there is a pending state change, we'd better deal with that first
-            consumeAndApplyPendingStateLocked();
+            consumeAndApplyPendingStateLocked(false);
 
             if (mCurrentVrService == null) {
                 return; // No active services
@@ -321,6 +385,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                 return;
             }
             pw.println("********* Dump of VrManagerService *********");
+            pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
             pw.println("Previous state transitions:\n");
             String tab = "  ";
             dumpStateTransitions(pw);
@@ -374,13 +439,17 @@ public class VrManagerService extends SystemService implements EnabledComponentC
         @Override
         public void setVrMode(boolean enabled, ComponentName packageName, int userId,
                 ComponentName callingPackage) {
-            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false);
+            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
         }
 
         @Override
-        public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId,
-                ComponentName callingPackage) {
-            VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true);
+        public void onSleepStateChanged(boolean isAsleep) {
+            VrManagerService.this.setSleepState(isAsleep);
+        }
+
+        @Override
+        public void onScreenStateChanged(boolean isScreenOn) {
+            VrManagerService.this.setScreenOn(isScreenOn);
         }
 
         @Override
@@ -424,6 +493,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
 
                 mComponentObserver.rebuildAll();
             }
+        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            synchronized (mLock) {
+                mVrModeAllowed = true;
+            }
         }
     }
 
@@ -512,7 +585,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
 
             boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
                     EnabledComponentsObserver.NO_ERROR);
-            if (!mVrModeEnabled && !enabled) {
+            boolean goingIntoVrMode = validUserComponent && enabled;
+            if (!mVrModeEnabled && !goingIntoVrMode) {
                 return validUserComponent; // Disabled -> Disabled transition does nothing.
             }
 
@@ -520,29 +594,39 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                     ? mCurrentVrService.getComponent().getPackageName() : null;
             final int oldUserId = mCurrentVrModeUser;
 
-            // Always send mode change events.
-            changeVrModeLocked(enabled);
+            // Notify system services and VR HAL of mode change.
+            changeVrModeLocked(goingIntoVrMode);
 
-            if (!enabled || !validUserComponent) {
-                // Unbind whatever is running
+            boolean nothingChanged = false;
+            if (!goingIntoVrMode) {
+                // Not going into VR mode, unbind whatever is running
                 if (mCurrentVrService != null) {
-                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
-                            mCurrentVrService.getUserId());
+                    Slog.i(TAG, "Leaving VR mode, disconnecting "
+                        + mCurrentVrService.getComponent() + " for user "
+                        + mCurrentVrService.getUserId());
                     mCurrentVrService.disconnect();
                     mCurrentVrService = null;
+                } else {
+                    nothingChanged = true;
                 }
             } else {
+                // Going into VR mode
                 if (mCurrentVrService != null) {
-                    // Unbind any running service that doesn't match the component/user selection
+                    // Unbind any running service that doesn't match the latest component/user
+                    // selection.
                     if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
-                        Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
-                                " for user " + mCurrentVrService.getUserId());
+                        Slog.i(TAG, "VR mode component changed to " + component
+                            + ", disconnecting " + mCurrentVrService.getComponent()
+                            + " for user " + mCurrentVrService.getUserId());
                         createAndConnectService(component, userId);
                         sendUpdatedCaller = true;
+                    } else {
+                        nothingChanged = true;
                     }
-                    // The service with the correct component/user is bound
+                    // The service with the correct component/user is already bound, do nothing.
                 } else {
-                    // Nothing was previously running, bind a new service
+                    // Nothing was previously running, bind a new service for the latest
+                    // component/user selection.
                     createAndConnectService(component, userId);
                     sendUpdatedCaller = true;
                 }
@@ -577,7 +661,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                     }
                 });
             }
-            logStateLocked();
+
+            if (!nothingChanged) {
+                logStateLocked();
+            }
 
             return validUserComponent;
         } finally {
@@ -663,16 +750,28 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
         // Don't clobber the user if permission set in current state explicitly
         if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
-            mContext.getPackageManager().grantRuntimePermission(pkg,
-                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            try {
+                mContext.getPackageManager().grantRuntimePermission(pkg,
+                        Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            } catch (IllegalArgumentException e) {
+                // Package was removed during update.
+                Slog.w(TAG, "Could not grant coarse location permission, package " + pkg
+                    + " was removed.");
+            }
         }
     }
 
     private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
         // Don't clobber the user if permission set in current state explicitly
         if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
-            mContext.getPackageManager().revokeRuntimePermission(pkg,
-                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            try {
+                mContext.getPackageManager().revokeRuntimePermission(pkg,
+                        Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+            } catch (IllegalArgumentException e) {
+                // Package was removed during update.
+                Slog.w(TAG, "Could not revoke coarse location permission, package " + pkg
+                    + " was removed.");
+            }
         }
     }
 
@@ -766,12 +865,29 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                 sBinderChecker);
     }
 
+    /**
+     * Apply the pending VR state. If no state is pending, disconnect any currently bound
+     * VR listener service.
+     */
     private void consumeAndApplyPendingStateLocked() {
+        consumeAndApplyPendingStateLocked(true);
+    }
+
+    /**
+     * Apply the pending VR state.
+     *
+     * @param disconnectIfNoPendingState if {@code true}, then any currently bound VR listener
+     *     service will be disconnected if no state is pending. If this is {@code false} then the
+     *     nothing will be changed when there is no pending state.
+     */
+    private void consumeAndApplyPendingStateLocked(boolean disconnectIfNoPendingState) {
         if (mPendingState != null) {
             updateCurrentVrServiceLocked(mPendingState.enabled,
                     mPendingState.targetPackageName, mPendingState.userId,
                     mPendingState.callingPackage);
             mPendingState = null;
+        } else if (disconnectIfNoPendingState) {
+            updateCurrentVrServiceLocked(false, null, 0, null);
         }
     }
 
@@ -822,13 +938,20 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     /*
      * Implementation of VrManagerInternal calls.  These are callable from system services.
      */
-
     private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
-            int userId, @NonNull ComponentName callingPackage, boolean immediate) {
+            int userId, @NonNull ComponentName callingPackage) {
 
         synchronized (mLock) {
+            VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
+            if (!mVrModeAllowed) {
+                // We're not allowed to be in VR mode.  Make this state pending.  This will be
+                // applied the next time we are allowed to enter VR mode unless it is superseded by
+                // another call.
+                mPendingState = pending;
+                return;
+            }
 
-            if (!enabled && mCurrentVrService != null && !immediate) {
+            if (!enabled && mCurrentVrService != null) {
                 // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
                 // and service bind/unbind in case we are immediately switching to another VR app.
                 if (mPendingState == null) {
@@ -836,7 +959,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                             PENDING_STATE_DELAY_MS);
                 }
 
-                mPendingState = new VrState(enabled, targetPackageName, userId, callingPackage);
+                mPendingState = pending;
                 return;
             } else {
                 mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE);