Add visibility control for the UiBlocker

The existing UiBlocker mechanism doesn't support additional visibility
control. With that, controllers that want to control their own
visibility won't be able to use UiBlocker.

Fixes: 223340393
Test: robotest
Change-Id: I2df2eb1ce77e2c94bb271a8b68cc8c6004df5c70
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index c90fe48..6cc09e2 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -121,10 +121,13 @@
 
     protected final String mPreferenceKey;
     protected UiBlockListener mUiBlockListener;
+    protected boolean mUiBlockerFinished;
     private boolean mIsForWork;
     @Nullable
     private UserHandle mWorkProfileUser;
     private int mMetricsCategory;
+    private boolean mIsFirstLaunch;
+    private boolean mPrefVisibility;
 
     /**
      * Instantiate a controller as specified controller type and user-defined key.
@@ -195,6 +198,8 @@
     public BasePreferenceController(Context context, String preferenceKey) {
         super(context);
         mPreferenceKey = preferenceKey;
+        mIsFirstLaunch = true;
+        mPrefVisibility = true;
         if (TextUtils.isEmpty(mPreferenceKey)) {
             throw new IllegalArgumentException("Preference key must be set");
         }
@@ -327,6 +332,13 @@
     }
 
     /**
+     * Set back the value of whether this is the first launch.
+     */
+    public void revokeFirstLaunch() {
+        mIsFirstLaunch = false;
+    }
+
+    /**
      * Launches the specified fragment for the work profile user if the associated
      * {@link Preference} is clicked.  Otherwise just forward it to the super class.
      *
@@ -378,6 +390,14 @@
         mUiBlockListener = uiBlockListener;
     }
 
+    public void setUiBlockerFinished(boolean isFinished) {
+        mUiBlockerFinished = isFinished;
+    }
+
+    public boolean getSavedPrefVisibility() {
+        return mPrefVisibility;
+    }
+
     /**
      * Listener to invoke when background job is finished
      */
@@ -428,4 +448,28 @@
     protected UserHandle getWorkProfileUser() {
         return mWorkProfileUser;
     }
+
+    /**
+     * Used for {@link BasePreferenceController} that implements {@link UiBlocker} to control the
+     * preference visibility.
+     */
+    protected void updatePreferenceVisibilityDelegate(Preference preference, boolean isVisible) {
+        if (mUiBlockerFinished || !mIsFirstLaunch) {
+            preference.setVisible(isVisible);
+            return;
+        }
+
+        savePrefVisibility(isVisible);
+
+        // Preferences that should be invisible have a high priority to be updated since the
+        // whole UI should be blocked/invisible. While those that should be visible will be
+        // updated once the blocker work is finished. That's done in DashboardFragment.
+        if (!isVisible) {
+            preference.setVisible(false);
+        }
+    }
+
+    private void savePrefVisibility(boolean isVisible) {
+        mPrefVisibility = isVisible;
+    }
 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 6ac0fa4..bff8226 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -250,6 +250,11 @@
             }
             mListeningToCategoryChange = false;
         }
+        mControllers.forEach(controller -> {
+            if (controller instanceof BasePreferenceController.UiBlocker) {
+                ((BasePreferenceController) controller).revokeFirstLaunch();
+            }
+        });
     }
 
     @Override
@@ -424,7 +429,14 @@
             for (AbstractPreferenceController controller : controllerList) {
                 final String key = controller.getPreferenceKey();
                 final Preference preference = findPreference(key);
-                if (preference != null) {
+                if (preference == null) {
+                    continue;
+                }
+                if (controller instanceof BasePreferenceController.UiBlocker) {
+                    final boolean prefVisible =
+                            ((BasePreferenceController) controller).getSavedPrefVisibility();
+                    preference.setVisible(visible && controller.isAvailable() && prefVisible);
+                } else {
                     preference.setVisible(visible && controller.isAvailable());
                 }
             }
@@ -496,6 +508,7 @@
     @Override
     public void onBlockerWorkFinished(BasePreferenceController controller) {
         mBlockerController.countDown(controller.getPreferenceKey());
+        controller.setUiBlockerFinished(mBlockerController.isBlockerFinished());
     }
 
     protected Preference createPreference(Tile tile) {
diff --git a/src/com/android/settings/dashboard/UiBlockerController.java b/src/com/android/settings/dashboard/UiBlockerController.java
index 710175b..b3729f1 100644
--- a/src/com/android/settings/dashboard/UiBlockerController.java
+++ b/src/com/android/settings/dashboard/UiBlockerController.java
@@ -37,7 +37,7 @@
  */
 public class UiBlockerController {
     private static final String TAG = "UiBlockerController";
-    private static final int TIMEOUT_MILLIS = 500;
+    private static final int TIMEOUT_MILLIS = 300;
 
     private CountDownLatch mCountDownLatch;
     private boolean mBlockerFinished;