Merge "Add StatusBarManager#disableForSetup(boolean) @SystemApi"
diff --git a/api/system-current.txt b/api/system-current.txt
index b9c1362..332ac2c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -530,6 +530,18 @@
     ctor public StatsManager.StatsUnavailableException(String, Throwable);
   }
 
+  public class StatusBarManager {
+    method public android.util.Pair<java.lang.Integer,java.lang.Integer> getDisableFlags();
+    method public void setDisabledForSetup(boolean);
+    field public static final int DISABLE2_NONE = 0; // 0x0
+    field public static final int DISABLE_EXPAND = 65536; // 0x10000
+    field public static final int DISABLE_HOME = 2097152; // 0x200000
+    field public static final int DISABLE_NONE = 0; // 0x0
+    field public static final int DISABLE_NOTIFICATION_ALERTS = 262144; // 0x40000
+    field public static final int DISABLE_RECENT = 16777216; // 0x1000000
+    field public static final int DISABLE_SEARCH = 33554432; // 0x2000000
+  }
+
   public final class Vr2dDisplayProperties implements android.os.Parcelable {
     ctor public Vr2dDisplayProperties(int, int, int);
     method public int describeContents();
@@ -1277,6 +1289,7 @@
     field public static final String ROLLBACK_SERVICE = "rollback";
     field public static final String SECURE_ELEMENT_SERVICE = "secure_element";
     field public static final String STATS_MANAGER = "stats";
+    field public static final String STATUS_BAR_SERVICE = "statusbar";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String VR_SERVICE = "vrmanager";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index aa4574b..1878d84 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -25,6 +26,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.View;
 
@@ -40,11 +42,12 @@
 public class StatusBarManager {
 
     /** @hide */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
     /** @hide */
     public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
     /** @hide */
+    @SystemApi
     public static final int DISABLE_NOTIFICATION_ALERTS
             = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
 
@@ -56,14 +59,17 @@
     /** @hide */
     public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
     /** @hide */
+    @SystemApi
     public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME;
     /** @hide */
+    @SystemApi
     public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
     /** @hide */
     public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
     /** @hide */
     public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
     /** @hide */
+    @SystemApi
     public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;
 
     /** @hide */
@@ -72,7 +78,7 @@
             View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT;
 
     /** @hide */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int DISABLE_NONE = 0x00000000;
 
     /** @hide */
@@ -116,6 +122,7 @@
     public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4;
 
     /** @hide */
+    @SystemApi
     public static final int DISABLE2_NONE = 0x00000000;
 
     /** @hide */
@@ -135,6 +142,21 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Disable2Flags {}
 
+    /**
+     * Default disable flags for setup
+     *
+     * @hide
+     */
+    public static final int DEFAULT_SETUP_DISABLE_FLAGS = DISABLE_NOTIFICATION_ALERTS
+            | DISABLE_HOME | DISABLE_EXPAND | DISABLE_RECENT | DISABLE_CLOCK | DISABLE_SEARCH;
+
+    /**
+     * Default disable2 flags for setup
+     *
+     * @hide
+     */
+    public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS;
+
     /** @hide */
     public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
     /** @hide */
@@ -340,6 +362,53 @@
         }
     }
 
+    /**
+     * Enable or disable status bar elements (notifications, clock) which are inappropriate during
+     * device setup.
+     *
+     * @param disabled whether to apply or remove the disabled flags
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setDisabledForSetup(boolean disabled) {
+        try {
+            final int userId = Binder.getCallingUserHandle().getIdentifier();
+            final IStatusBarService svc = getService();
+            if (svc != null) {
+                svc.disableForUser(disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE,
+                        mToken, mContext.getPackageName(), userId);
+                svc.disable2ForUser(disabled ? DEFAULT_SETUP_DISABLE2_FLAGS : DISABLE2_NONE,
+                        mToken, mContext.getPackageName(), userId);
+            }
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the currently applied StatusBar disable flags
+     *
+     * @return a pair of Integers in the form of (disable, disable2)
+     *
+     * @hide
+     */
+    @SystemApi
+    public Pair<Integer, Integer> getDisableFlags() {
+        try {
+            final int userId = Binder.getCallingUserHandle().getIdentifier();
+            final IStatusBarService svc = getService();
+            int[] flags = new int[] {0, 0};
+            if (svc != null) {
+                flags = svc.getDisableFlags(mToken, userId);
+            }
+
+            return new Pair<Integer, Integer>(flags[0], flags[1]);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public static String windowStateToString(int state) {
         if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d9d0ee9..adc1bf2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3621,9 +3621,10 @@
      *
      * @see #getSystemService(String)
      * @see android.app.StatusBarManager
+     *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final String STATUS_BAR_SERVICE = "statusbar";
 
     /**
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index d355745..9df37ad 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -38,6 +38,7 @@
     void disableForUser(int what, IBinder token, String pkg, int userId);
     void disable2(int what, IBinder token, String pkg);
     void disable2ForUser(int what, IBinder token, String pkg, int userId);
+    int[] getDisableFlags(IBinder token, int userId);
     void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
     void setIconVisibility(String slot, boolean visible);
     void removeIcon(String slot);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 9617529..d932a40 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -19,6 +19,7 @@
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.annotation.Nullable;
 import android.app.ActivityThread;
 import android.app.Notification;
 import android.app.StatusBarManager;
@@ -42,10 +43,12 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -669,7 +672,7 @@
     // TODO(b/117478341): make it aware of multi-display if needed.
     /**
      * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
-     * To re-enable everything, pass {@link #DISABLE_NONE}.
+     * To re-enable everything, pass {@link #DISABLE2_NONE}.
      *
      * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags.
      */
@@ -707,7 +710,7 @@
         final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2);
 
         // TODO(b/113914868): investigation log for disappearing home button
-        if (whichFlag == 1 && pkg.contains("systemui")) {
+        if (whichFlag == 1 && pkg != null && pkg.contains("systemui")) {
             String disabledData = "{ ";
             for (int i = 0; i < mDisableRecords.size(); i++) {
                 DisableRecord tok = mDisableRecords.get(i);
@@ -733,6 +736,30 @@
         }
     }
 
+    /**
+     * Get the currently applied disable flags, in the form of one Pair<Integer, Integer>.
+     *
+     * @return pair of disable flags in the form of (disabled1, disabled2), where (0, 0) indicates
+     * no flags are set for this token.
+     */
+    @Override
+    public int[] getDisableFlags(IBinder token, int userId) {
+        enforceStatusBar();
+
+        int disable1 = 0;
+        int disable2 = 0;
+        synchronized (mLock) {
+            // Find a matching record if it exists
+            DisableRecord record = findMatchingRecordLocked(token, userId).second;
+            if (record != null) {
+                disable1 = record.what1;
+                disable2 = record.what2;
+            }
+        }
+
+        return new int[] {disable1, disable2};
+    }
+
     @Override
     public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
             String contentDescription) {
@@ -1305,7 +1332,7 @@
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
-        (new StatusBarShellCommand(this)).exec(
+        (new StatusBarShellCommand(this, mContext)).exec(
                 this, in, out, err, args, callback, resultReceiver);
     }
 
@@ -1325,16 +1352,9 @@
         }
 
         // Find matching record, if any
-        final int N = mDisableRecords.size();
-        DisableRecord record = null;
-        int i;
-        for (i = 0; i < N; i++) {
-            DisableRecord r = mDisableRecords.get(i);
-            if (r.token == token && r.userId == userId) {
-                record = r;
-                break;
-            }
-        }
+        Pair<Integer, DisableRecord> match = findMatchingRecordLocked(token, userId);
+        int i = match.first;
+        DisableRecord record = match.second;
 
         // Remove record if binder is already dead
         if (!token.isBinderAlive()) {
@@ -1361,6 +1381,23 @@
         mDisableRecords.add(record);
     }
 
+    @Nullable
+    @GuardedBy("mLock")
+    private Pair<Integer, DisableRecord> findMatchingRecordLocked(IBinder token, int userId) {
+        final int numRecords = mDisableRecords.size();
+        DisableRecord record = null;
+        int i;
+        for (i = 0; i < numRecords; i++) {
+            DisableRecord r = mDisableRecords.get(i);
+            if (r.token == token && r.userId == userId) {
+                record = r;
+                break;
+            }
+        }
+
+        return new Pair<Integer, DisableRecord>(i, record);
+    }
+
     // lock on mDisableRecords
     int gatherDisableActionsLocked(int userId, int which) {
         final int N = mDisableRecords.size();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
index 4e20f01..ff01d46 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
@@ -14,21 +14,31 @@
 
 package com.android.server.statusbar;
 
+import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE2_FLAGS;
+import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE_FLAGS;
+import static android.app.StatusBarManager.DISABLE2_NONE;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
 import android.content.ComponentName;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.service.quicksettings.TileService;
 
-import com.android.internal.statusbar.IStatusBarService;
-
 import java.io.PrintWriter;
 
 public class StatusBarShellCommand extends ShellCommand {
 
-    private final StatusBarManagerService mInterface;
+    private static final IBinder sToken = new StatusBarShellCommandToken();
 
-    public StatusBarShellCommand(StatusBarManagerService service) {
+    private final StatusBarManagerService mInterface;
+    private final Context mContext;
+
+    public StatusBarShellCommand(StatusBarManagerService service, Context context) {
         mInterface = service;
+        mContext = context;
     }
 
     @Override
@@ -56,6 +66,8 @@
                     return 0;
                 case "get-status-icons":
                     return runGetStatusIcons();
+                case "disable-for-setup":
+                    return runDisableForSetup();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -104,6 +116,22 @@
         return 0;
     }
 
+    private int runDisableForSetup() {
+        String arg = getNextArgRequired();
+        String pkg = mContext.getPackageName();
+        boolean disable = Boolean.parseBoolean(arg);
+
+        if (disable) {
+            mInterface.disable(DEFAULT_SETUP_DISABLE_FLAGS, sToken, pkg);
+            mInterface.disable2(DEFAULT_SETUP_DISABLE2_FLAGS, sToken, pkg);
+        } else {
+            mInterface.disable(DISABLE_NONE, sToken, pkg);
+            mInterface.disable2(DISABLE2_NONE, sToken, pkg);
+        }
+
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
@@ -135,5 +163,14 @@
         pw.println("  get-status-icons");
         pw.println("    Print the list of status bar icons and the order they appear in");
         pw.println("");
+        pw.println("  disable-for-setup DISABLE");
+        pw.println("    If true, disable status bar components unsuitable for device setup");
+        pw.println("");
+    }
+
+    /**
+     * Token to send to StatusBarManagerService for disable* commands
+     */
+    private static final class StatusBarShellCommandToken extends Binder {
     }
 }