Merge "Refactoring of auto fill - lifecycle, auth, improvements"
diff --git a/api/system-current.txt b/api/system-current.txt
index a8000dc..4a16b839 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6204,6 +6204,10 @@
     method public void onDetached();
   }
 
+  public class VrManager {
+    method public void setPersistentVrModeEnabled(boolean);
+  }
+
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -9006,6 +9010,7 @@
     field public static final java.lang.String USB_SERVICE = "usb";
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
+    field public static final java.lang.String VR_SERVICE = "vrmanager";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
     field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5a75a67..fc1d613 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -115,6 +115,7 @@
 import android.service.autofill.IAutoFillManagerService;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.service.vr.IVrManager;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -814,6 +815,14 @@
                 IAutoFillManagerService service = IAutoFillManagerService.Stub.asInterface(b);
                 return new AutoFillManager(ctx, service);
             }});
+
+        registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
+            @Override
+            public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getServiceOrThrow(Context.VR_SERVICE);
+                return new VrManager(IVrManager.Stub.asInterface(b));
+            }
+        });
     }
 
     /**
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
new file mode 100644
index 0000000..a0b0eea
--- /dev/null
+++ b/core/java/android/app/VrManager.java
@@ -0,0 +1,44 @@
+package android.app;
+
+
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.service.vr.IVrManager;
+
+/**
+ * Used to control aspects of a devices Virtual Reality (VR) capabilities.
+ * <p>
+ * You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ * @hide
+ */
+@SystemApi
+public class VrManager {
+    private final IVrManager mService;
+
+    /**
+     * {@hide}
+     */
+    public VrManager(IVrManager service) {
+        mService = service;
+    }
+
+    /**
+     * 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.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @see Activity#setVrModeEnabled(boolean, ComponentName)
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    public void setPersistentVrModeEnabled(boolean enabled) {
+        try {
+            mService.setPersistentVrModeEnabled(enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f610a29..a7d5ac6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -35,6 +35,7 @@
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.Notification;
+import android.app.VrManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -3764,6 +3765,16 @@
     public static final String OVERLAY_SERVICE = "overlay";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link VrManager} for accessing the VR service.
+     *
+     * @see #getSystemService
+     * @hide
+     */
+    @SystemApi
+    public static final String VR_SERVICE = "vrmanager";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 62ecab3..10e4177 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -42,5 +42,13 @@
      */
     boolean getVrModeState();
 
+    /**
+     * 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.
+     *
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    void setPersistentVrModeEnabled(in boolean enabled);
 }
 
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 0fc1900..45b7baf 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -79,4 +79,13 @@
      *       given in {@link android.service.vr.VrModeException} on failure.
      */
     public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
+
+    /**
+     * 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.
+     *
+     * @param enabled true if the device should be placed in persistent VR mode.
+     */
+    public abstract void setPersistentVrModeEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 8368b05..51c4ce31 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -20,15 +20,10 @@
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
 import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
@@ -53,7 +48,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
-import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -69,8 +63,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
-import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -121,8 +113,10 @@
     // State protected by mLock
     private boolean mVrModeAllowed;
     private boolean mVrModeEnabled;
+    private boolean mPersistentVrModeEnabled;
     private EnabledComponentsObserver mComponentObserver;
     private ManagedApplicationService mCurrentVrService;
+    private ComponentName mDefaultVrService;
     private Context mContext;
     private ComponentName mCurrentVrModeComponent;
     private int mCurrentVrModeUser;
@@ -157,6 +151,10 @@
             if (mVrModeAllowed) {
                 consumeAndApplyPendingStateLocked();
             } else {
+                // Disable persistent mode when VR mode isn't allowed, allows an escape hatch to
+                // exit persistent VR mode when screen is turned off.
+                mPersistentVrModeEnabled = false;
+
                 // Set pending state to current state.
                 mPendingState = (mVrModeEnabled && mCurrentVrService != null)
                     ? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
@@ -378,6 +376,12 @@
         }
 
         @Override
+        public void setPersistentVrModeEnabled(boolean enabled) {
+            enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+            VrManagerService.this.setPersistentVrModeEnabled(enabled);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -387,6 +391,8 @@
             }
             pw.println("********* Dump of VrManagerService *********");
             pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
+            pw.println("Persistent VR mode is currently: " +
+                    ((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
             pw.println("Previous state transitions:\n");
             String tab = "  ";
             dumpStateTransitions(pw);
@@ -462,6 +468,11 @@
         public int hasVrPackage(ComponentName packageName, int userId) {
             return VrManagerService.this.hasVrPackage(packageName, userId);
         }
+
+        @Override
+        public void setPersistentVrModeEnabled(boolean enabled) {
+            VrManagerService.this.setPersistentVrModeEnabled(enabled);
+        }
     }
 
     public VrManagerService(Context context) {
@@ -494,6 +505,15 @@
 
                 mComponentObserver.rebuildAll();
             }
+
+            //TODO: something more robust than picking the first one
+            ArraySet<ComponentName> defaultVrComponents =
+                    SystemConfig.getInstance().getDefaultVrComponents();
+            if (defaultVrComponents.size() > 0) {
+                mDefaultVrService = defaultVrComponents.valueAt(0);
+            } else {
+                Slog.i(TAG, "No default vr listener service found.");
+            }
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             synchronized (mLock) {
                 mVrModeAllowed = true;
@@ -637,8 +657,8 @@
                 }
             }
 
+            mCurrentVrModeComponent = calling;
             if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
-                mCurrentVrModeComponent = calling;
                 sendUpdatedCaller = true;
             }
 
@@ -947,7 +967,25 @@
             int userId, @NonNull ComponentName callingPackage) {
 
         synchronized (mLock) {
-            VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
+            VrState pending;
+            ComponentName targetListener;
+            ComponentName foregroundVrComponent;
+
+            // If the device is in persistent VR mode, then calls to disable VR mode are ignored,
+            // and the system default VR listener is used.
+            boolean targetEnabledState = enabled || mPersistentVrModeEnabled;
+            if (!enabled && mPersistentVrModeEnabled) {
+                targetListener = mDefaultVrService;
+
+                // Current foreground component isn't a VR one (in 2D app case)
+                foregroundVrComponent = null;
+            } else {
+                targetListener = targetPackageName;
+                foregroundVrComponent = callingPackage;
+            }
+            pending = new VrState(
+                    targetEnabledState, targetListener, userId, foregroundVrComponent);
+
             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
@@ -956,7 +994,7 @@
                 return;
             }
 
-            if (!enabled && mCurrentVrService != null) {
+            if (!targetEnabledState && 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) {
@@ -971,7 +1009,19 @@
                 mPendingState = null;
             }
 
-            updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
+            updateCurrentVrServiceLocked(
+                    targetEnabledState, targetListener, userId, foregroundVrComponent);
+        }
+    }
+
+    private void setPersistentVrModeEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mPersistentVrModeEnabled = enabled;
+
+            // Disabling persistent mode when not showing a VR should disable the overall vr mode.
+            if (!enabled && mCurrentVrModeComponent == null) {
+                setVrMode(false, null, 0, null);
+            }
         }
     }