Merge "Add settings observing for vibrate icon to Keyguard" into tm-dev am: 2540293518

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18602315

Change-Id: Ic5d40b4a1e7c77ca3be9175247f87c2006b529bf
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 779c6b4..def574c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -23,12 +23,16 @@
 import android.animation.ValueAnimator;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.hardware.biometrics.BiometricSourceType;
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.MathUtils;
 import android.view.View;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.keyguard.CarrierTextController;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -36,6 +40,7 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -45,6 +50,7 @@
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
 import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
@@ -54,10 +60,12 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.util.ViewController;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -98,6 +106,9 @@
     private final StatusBarUserSwitcherFeatureController mFeatureController;
     private final StatusBarUserSwitcherController mUserSwitcherController;
     private final StatusBarUserInfoTracker mStatusBarUserInfoTracker;
+    private final SecureSettings mSecureSettings;
+    private final Executor mMainExecutor;
+    private final Object mLock = new Object();
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -206,7 +217,7 @@
                 }
             };
 
-    private final List<String> mBlockedIcons;
+    private final List<String> mBlockedIcons = new ArrayList<>();
     private final int mNotificationsHeaderCollideDistance;
 
     private boolean mBatteryListening;
@@ -255,7 +266,9 @@
             UserManager userManager,
             StatusBarUserSwitcherFeatureController featureController,
             StatusBarUserSwitcherController userSwitcherController,
-            StatusBarUserInfoTracker statusBarUserInfoTracker
+            StatusBarUserInfoTracker statusBarUserInfoTracker,
+            SecureSettings secureSettings,
+            @Main Executor mainExecutor
     ) {
         super(view);
         mCarrierTextController = carrierTextController;
@@ -277,6 +290,8 @@
         mFeatureController = featureController;
         mUserSwitcherController = userSwitcherController;
         mStatusBarUserInfoTracker = statusBarUserInfoTracker;
+        mSecureSettings = secureSettings;
+        mMainExecutor = mainExecutor;
 
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
         mKeyguardStateController.addCallback(
@@ -292,8 +307,7 @@
         );
 
         Resources r = getResources();
-        mBlockedIcons = Arrays.asList(r.getStringArray(
-                R.array.config_keyguard_statusbar_icon_blocklist));
+        updateBlockedIcons();
         mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
                 R.dimen.header_notifications_collide_distance);
 
@@ -321,11 +335,16 @@
         if (mTintedIconManager == null) {
             mTintedIconManager =
                     mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
-            mTintedIconManager.setBlockList(mBlockedIcons);
+            mTintedIconManager.setBlockList(getBlockedIcons());
             mStatusBarIconController.addIconGroup(mTintedIconManager);
         }
         mView.setOnApplyWindowInsetsListener(
                 (view, windowInsets) -> mView.updateWindowInsets(windowInsets, mInsetsProvider));
+        mSecureSettings.registerContentObserverForUser(
+                Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
+                false,
+                mVolumeSettingObserver,
+                UserHandle.USER_ALL);
         updateUserSwitcher();
         onThemeChanged();
     }
@@ -337,6 +356,7 @@
         mUserInfoController.removeCallback(mOnUserInfoChangedListener);
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+        mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
         if (mTintedIconManager != null) {
             mStatusBarIconController.removeIconGroup(mTintedIconManager);
         }
@@ -486,8 +506,32 @@
                 R.bool.qs_show_user_switcher_for_single_user)));
     }
 
+    @VisibleForTesting
+    void updateBlockedIcons() {
+        List<String> newBlockList = StatusBarIconBlocklistKt
+                .getStatusBarIconBlocklist(getResources(), mSecureSettings);
+
+        synchronized (mLock) {
+            mBlockedIcons.clear();
+            mBlockedIcons.addAll(newBlockList);
+        }
+
+        mMainExecutor.execute(() -> {
+            if (mTintedIconManager != null) {
+                mTintedIconManager.setBlockList(getBlockedIcons());
+            }
+        });
+    }
+
+    @VisibleForTesting
+    List<String> getBlockedIcons() {
+        synchronized (mLock) {
+            return new ArrayList<>(mBlockedIcons);
+        }
+    }
+
     /**
-     * Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
+      Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
      * whether heads up is visible.
      */
     public void updateForHeadsUp() {
@@ -533,4 +577,11 @@
         mExplicitAlpha = alpha;
         updateViewState();
     }
+
+    private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateBlockedIcons();
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt
new file mode 100644
index 0000000..b845bad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone.fragment
+
+import android.content.res.Resources
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.internal.R
+import com.android.systemui.util.settings.SecureSettings
+
+/**
+ * Centralize the logic for the status bar / keyguard status bar icon blocklist. The default is
+ * loaded from the config, and we currently support a system setting for the vibrate icon. It's
+ * pretty likely that we would end up supporting more user-configurable settings in the future, so
+ * breaking this out into its own file for now.
+ *
+ * Note for the future: it might be reasonable to turn this into its own class that can listen to
+ * the system setting and execute a callback when it changes instead of having multiple content
+ * observers.
+ */
+fun getStatusBarIconBlocklist(
+    res: Resources,
+    settings: SecureSettings
+): List<String> {
+    // Load the default blocklist from res
+    val blocklist = res.getStringArray(
+            com.android.systemui.R.array.config_collapsed_statusbar_icon_blocklist).toList()
+
+    val vibrateIconSlot: String = res.getString(R.string.status_bar_volume)
+    val showVibrateIcon = settings.getIntForUser(
+            Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
+            0,
+            UserHandle.USER_CURRENT) == 0
+
+    // Filter out vibrate icon from the blocklist if the setting is on
+    return blocklist.filter { icon ->
+        !icon.equals(vibrateIconSlot) || showVibrateIcon
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 39d5a16..4e1a708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -22,6 +22,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.clearInvocations;
@@ -29,7 +31,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
@@ -55,6 +59,9 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -108,10 +115,12 @@
     private StatusBarUserSwitcherController mStatusBarUserSwitcherController;
     @Mock
     private StatusBarUserInfoTracker mStatusBarUserInfoTracker;
+    @Mock private SecureSettings mSecureSettings;
 
     private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
     private KeyguardStatusBarView mKeyguardStatusBarView;
     private KeyguardStatusBarViewController mController;
+    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setup() throws Exception {
@@ -150,7 +159,9 @@
                 mUserManager,
                 mStatusBarUserSwitcherFeatureController,
                 mStatusBarUserSwitcherController,
-                mStatusBarUserInfoTracker
+                mStatusBarUserInfoTracker,
+                mSecureSettings,
+                mFakeExecutor
         );
     }
 
@@ -420,6 +431,39 @@
         assertThat(mKeyguardStatusBarView.isKeyguardUserAvatarEnabled()).isTrue();
     }
 
+    @Test
+    public void testBlockedIcons_obeysSettingForVibrateIcon_settingOff() {
+        String str = mContext.getString(com.android.internal.R.string.status_bar_volume);
+
+        // GIVEN the setting is off
+        when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0))
+                .thenReturn(0);
+
+        // WHEN CollapsedStatusBarFragment builds the blocklist
+        mController.updateBlockedIcons();
+
+        // THEN status_bar_volume SHOULD be present in the list
+        boolean contains = mController.getBlockedIcons().contains(str);
+        assertTrue(contains);
+    }
+
+    @Test
+    public void testBlockedIcons_obeysSettingForVibrateIcon_settingOn() {
+        String str = mContext.getString(com.android.internal.R.string.status_bar_volume);
+
+        // GIVEN the setting is ON
+        when(mSecureSettings.getIntForUser(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0,
+                UserHandle.USER_CURRENT))
+                .thenReturn(1);
+
+        // WHEN CollapsedStatusBarFragment builds the blocklist
+        mController.updateBlockedIcons();
+
+        // THEN status_bar_volume SHOULD NOT be present in the list
+        boolean contains = mController.getBlockedIcons().contains(str);
+        assertFalse(contains);
+    }
+
     private void updateStateToNotKeyguard() {
         updateStatusBarState(SHADE);
     }