Fix DeviceProvisioned on PhoneStatusBarPolicy

With the new DeviceProvisionedController, adding the callback does not
immediately call it back. Instead, we need to retrieve the value on
subscription. This was causing the alarm icon not to show in QS headers
(it's blocked in other surfaces using a blocklist).

Keep it disabled (using ignore) for regular headers, but do not ignore
it in the combined headers.

Test: atest PhoneStatusBarPolicyTest QuickStatusBarHeaderControllerTest
Test: atest com.android.systemui.shade
Fixes: 204159738
Change-Id: I2eabfa6c61ed9eea66c9127449250919618a47fd
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 2a6cf66..b585961 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -128,6 +128,8 @@
         mPrivacyIconsController.setChipVisibilityListener(this);
         mIconContainer.addIgnoredSlot(
                 getResources().getString(com.android.internal.R.string.status_bar_managed_profile));
+        mIconContainer.addIgnoredSlot(
+                getResources().getString(com.android.internal.R.string.status_bar_alarm_clock));
         mIconContainer.setShouldRestrictIcons(false);
         mStatusBarIconController.addIconGroup(mIconManager);
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index fab70fc..6b32daf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -270,6 +270,14 @@
         qsCarrierGroupController = qsCarrierGroupControllerBuilder
             .setQSCarrierGroup(qsCarrierGroup)
             .build()
+
+        if (!combinedHeaders) {
+            // In the new header, we display alarm icon but we ignore it when not using the new
+            // headers.
+            iconContainer.addIgnoredSlot(
+                    context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+            )
+        }
     }
 
     override fun onViewAttached() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 290df3e..48e58fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -127,7 +128,7 @@
     private final DateFormatUtil mDateFormatUtil;
     private final TelecomManager mTelecomManager;
 
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler;
     private final CastController mCast;
     private final HotspotController mHotspot;
     private final NextAlarmController mNextAlarmController;
@@ -166,7 +167,7 @@
     @Inject
     public PhoneStatusBarPolicy(StatusBarIconController iconController,
             CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher,
-            @UiBackground Executor uiBgExecutor, @Main Resources resources,
+            @UiBackground Executor uiBgExecutor, @Main Looper looper, @Main Resources resources,
             CastController castController, HotspotController hotspotController,
             BluetoothController bluetoothController, NextAlarmController nextAlarmController,
             UserInfoController userInfoController, RotationLockController rotationLockController,
@@ -185,6 +186,7 @@
         mIconController = iconController;
         mCommandQueue = commandQueue;
         mBroadcastDispatcher = broadcastDispatcher;
+        mHandler = new Handler(looper);
         mResources = resources;
         mCast = castController;
         mHotspot = hotspotController;
@@ -332,6 +334,7 @@
         mRotationLockController.addCallback(this);
         mBluetooth.addCallback(this);
         mProvisionedController.addCallback(this);
+        mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
         mZenController.addCallback(this);
         mCast.addCallback(mCastCallback);
         mHotspot.addCallback(mHotspotCallback);
@@ -562,6 +565,7 @@
                     mHandler.post(() -> {
                         updateAlarm();
                         updateManagedProfile();
+                        onUserSetupChanged();
                     });
                 }
             };
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index cb4f08e..eb907bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -192,6 +192,14 @@
         verify(view).setIsSingleCarrier(false)
     }
 
+    @Test
+    fun testAlarmIconIgnored() {
+        controller.init()
+
+        verify(iconContainer).addIgnoredSlot(
+                mContext.getString(com.android.internal.R.string.status_bar_alarm_clock))
+    }
+
     private fun stubViews() {
         `when`(view.findViewById<View>(anyInt())).thenReturn(mockView)
         `when`(view.findViewById<QSCarrierGroup>(R.id.carrier_group)).thenReturn(qsCarrierGroup)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index 20c6d9a..e85ffb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -607,6 +607,13 @@
         verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
     }
 
+    @Test
+    fun alarmIconNotIgnored() {
+        verify(statusIcons, never()).addIgnoredSlot(
+                context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+        )
+    }
+
     private fun createWindowInsets(
         topCutout: Rect? = Rect()
     ): WindowInsets {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index eeb61bc..8511443 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -191,4 +191,11 @@
         verify(date).setTextAppearance(R.style.TextAppearance_QS_Status)
         verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers)
     }
+
+    @Test
+    fun alarmIconIgnored() {
+        verify(statusIcons).addIgnoredSlot(
+                context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
new file mode 100644
index 0000000..64dee95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -0,0 +1,230 @@
+/*
+ * 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
+
+import android.app.AlarmManager
+import android.app.IActivityManager
+import android.app.admin.DevicePolicyManager
+import android.content.SharedPreferences
+import android.os.UserManager
+import android.telecom.TelecomManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.privacy.PrivacyItemController
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.policy.BluetoothController
+import com.android.systemui.statusbar.policy.CastController
+import com.android.systemui.statusbar.policy.DataSaverController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HotspotController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.statusbar.policy.NextAlarmController
+import com.android.systemui.statusbar.policy.RotationLockController
+import com.android.systemui.statusbar.policy.SensorPrivacyController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.ZenModeController
+import com.android.systemui.util.RingerModeTracker
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.DateFormatUtil
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Answers
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+@SmallTest
+class PhoneStatusBarPolicyTest : SysuiTestCase() {
+
+    companion object {
+        private const val ALARM_SLOT = "alarm"
+    }
+
+    @Mock
+    private lateinit var iconController: StatusBarIconController
+    @Mock
+    private lateinit var commandQueue: CommandQueue
+    @Mock
+    private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock
+    private lateinit var castController: CastController
+    @Mock
+    private lateinit var hotspotController: HotspotController
+    @Mock
+    private lateinit var bluetoothController: BluetoothController
+    @Mock
+    private lateinit var nextAlarmController: NextAlarmController
+    @Mock
+    private lateinit var userInfoController: UserInfoController
+    @Mock
+    private lateinit var rotationLockController: RotationLockController
+    @Mock
+    private lateinit var dataSaverController: DataSaverController
+    @Mock
+    private lateinit var zenModeController: ZenModeController
+    @Mock
+    private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock
+    private lateinit var keyguardStateController: KeyguardStateController
+    @Mock
+    private lateinit var locationController: LocationController
+    @Mock
+    private lateinit var sensorPrivacyController: SensorPrivacyController
+    @Mock
+    private lateinit var iActivityManager: IActivityManager
+    @Mock
+    private lateinit var alarmManager: AlarmManager
+    @Mock
+    private lateinit var userManager: UserManager
+    @Mock
+    private lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock
+    private lateinit var recordingController: RecordingController
+    @Mock
+    private lateinit var telecomManager: TelecomManager
+    @Mock
+    private lateinit var sharedPreferences: SharedPreferences
+    @Mock
+    private lateinit var dateFormatUtil: DateFormatUtil
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private lateinit var ringerModeTracker: RingerModeTracker
+    @Mock
+    private lateinit var privacyItemController: PrivacyItemController
+    @Mock
+    private lateinit var privacyLogger: PrivacyLogger
+    @Captor
+    private lateinit var alarmCallbackCaptor:
+            ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
+
+    private lateinit var executor: FakeExecutor
+    private lateinit var statusBarPolicy: PhoneStatusBarPolicy
+    private lateinit var testableLooper: TestableLooper
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        executor = FakeExecutor(FakeSystemClock())
+        testableLooper = TestableLooper.get(this)
+        context.orCreateTestableResources.addOverride(
+                com.android.internal.R.string.status_bar_alarm_clock,
+                ALARM_SLOT
+        )
+        statusBarPolicy = createStatusBarPolicy()
+    }
+
+    @Test
+    fun testDeviceNotProvisioned_alarmIconNotShown() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+        statusBarPolicy.init()
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    @Test
+    fun testDeviceProvisioned_alarmIconShown() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+        statusBarPolicy.init()
+
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    @Test
+    fun testDeviceProvisionedChanged_alarmIconShownAfterCurrentUserSetup() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+        statusBarPolicy.init()
+
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+        statusBarPolicy.onUserSetupChanged()
+        verify(iconController).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    private fun createAlarmInfo(): AlarmManager.AlarmClockInfo {
+        return AlarmManager.AlarmClockInfo(10L, null)
+    }
+
+    private fun createStatusBarPolicy(): PhoneStatusBarPolicy {
+        return PhoneStatusBarPolicy(
+                iconController,
+                commandQueue,
+                broadcastDispatcher,
+                executor,
+                testableLooper.looper,
+                context.resources,
+                castController,
+                hotspotController,
+                bluetoothController,
+                nextAlarmController,
+                userInfoController,
+                rotationLockController,
+                dataSaverController,
+                zenModeController,
+                deviceProvisionedController,
+                keyguardStateController,
+                locationController,
+                sensorPrivacyController,
+                iActivityManager,
+                alarmManager,
+                userManager,
+                devicePolicyManager,
+                recordingController,
+                telecomManager,
+                /* displayId = */ 0,
+                sharedPreferences,
+                dateFormatUtil,
+                ringerModeTracker,
+                privacyItemController,
+                privacyLogger
+        )
+    }
+}