1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.qs.tiles 18 19 import android.app.Dialog 20 import android.content.ContextWrapper 21 import android.content.SharedPreferences 22 import android.os.Handler 23 import android.platform.test.annotations.DisableFlags 24 import android.platform.test.flag.junit.FlagsParameterization 25 import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf 26 import android.provider.Settings 27 import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS 28 import android.provider.Settings.Global.ZEN_MODE_OFF 29 import android.testing.TestableLooper 30 import android.view.ContextThemeWrapper 31 import androidx.test.filters.SmallTest 32 import com.android.internal.logging.MetricsLogger 33 import com.android.systemui.SysuiTestCase 34 import com.android.systemui.animation.DialogTransitionAnimator 35 import com.android.systemui.animation.Expandable 36 import com.android.systemui.classifier.FalsingManagerFake 37 import com.android.systemui.plugins.ActivityStarter 38 import com.android.systemui.plugins.qs.QSTile 39 import com.android.systemui.plugins.statusbar.StatusBarStateController 40 import com.android.systemui.qs.QSHost 41 import com.android.systemui.qs.QsEventLogger 42 import com.android.systemui.qs.flags.QSComposeFragment 43 import com.android.systemui.qs.flags.QsInCompose.isEnabled 44 import com.android.systemui.qs.logging.QSLogger 45 import com.android.systemui.qs.tileimpl.QSTileImpl 46 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIconWithRes 47 import com.android.systemui.res.R 48 import com.android.systemui.statusbar.policy.ZenModeController 49 import com.android.systemui.util.mockito.any 50 import com.android.systemui.util.mockito.nullable 51 import com.android.systemui.util.settings.FakeSettings 52 import com.android.systemui.util.settings.SecureSettings 53 import com.google.common.truth.Truth.assertThat 54 import java.io.File 55 import org.junit.After 56 import org.junit.Before 57 import org.junit.Test 58 import org.junit.runner.RunWith 59 import org.mockito.Mock 60 import org.mockito.Mockito.anyBoolean 61 import org.mockito.Mockito.never 62 import org.mockito.Mockito.verify 63 import org.mockito.Mockito.`when` as whenever 64 import org.mockito.MockitoAnnotations 65 import platform.test.runner.parameterized.ParameterizedAndroidJunit4 66 import platform.test.runner.parameterized.Parameters 67 68 @SmallTest 69 @RunWith(ParameterizedAndroidJunit4::class) 70 @TestableLooper.RunWithLooper(setAsMainLooper = true) 71 @DisableFlags(android.app.Flags.FLAG_MODES_UI) 72 class DndTileTest(flags: FlagsParameterization) : SysuiTestCase() { 73 74 companion object { 75 private const val DEFAULT_USER = 0 76 private const val KEY = Settings.Secure.ZEN_DURATION 77 78 @JvmStatic 79 @Parameters(name = "{0}") getParamsnull80 fun getParams(): List<FlagsParameterization> { 81 return allCombinationsOf(QSComposeFragment.FLAG_NAME) 82 } 83 } 84 85 init { 86 mSetFlagsRule.setFlagsParameterization(flags) 87 } 88 89 @Mock private lateinit var qsHost: QSHost 90 91 @Mock private lateinit var metricsLogger: MetricsLogger 92 93 @Mock private lateinit var statusBarStateController: StatusBarStateController 94 95 @Mock private lateinit var activityStarter: ActivityStarter 96 97 @Mock private lateinit var qsLogger: QSLogger 98 99 @Mock private lateinit var uiEventLogger: QsEventLogger 100 101 @Mock private lateinit var zenModeController: ZenModeController 102 103 @Mock private lateinit var sharedPreferences: SharedPreferences 104 105 @Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator 106 107 @Mock private lateinit var hostDialog: Dialog 108 109 @Mock private lateinit var expandable: Expandable 110 111 @Mock private lateinit var controller: DialogTransitionAnimator.Controller 112 113 private lateinit var secureSettings: SecureSettings 114 private lateinit var testableLooper: TestableLooper 115 private lateinit var tile: DndTile 116 117 @Before setUpnull118 fun setUp() { 119 MockitoAnnotations.initMocks(this) 120 testableLooper = TestableLooper.get(this) 121 secureSettings = FakeSettings() 122 123 whenever(qsHost.userId).thenReturn(DEFAULT_USER) 124 125 val wrappedContext = 126 object : 127 ContextWrapper(ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)) { 128 override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { 129 return sharedPreferences 130 } 131 } 132 whenever(qsHost.context).thenReturn(wrappedContext) 133 whenever(expandable.dialogTransitionController(any())).thenReturn(controller) 134 135 tile = 136 DndTile( 137 qsHost, 138 uiEventLogger, 139 testableLooper.looper, 140 Handler(testableLooper.looper), 141 FalsingManagerFake(), 142 metricsLogger, 143 statusBarStateController, 144 activityStarter, 145 qsLogger, 146 zenModeController, 147 sharedPreferences, 148 secureSettings, 149 mDialogTransitionAnimator, 150 ) 151 } 152 153 @After tearDownnull154 fun tearDown() { 155 tile.destroy() 156 testableLooper.processAllMessages() 157 } 158 159 @Test testForceExpandIcon_durationAskAlways_truenull160 fun testForceExpandIcon_durationAskAlways_true() { 161 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 162 163 tile.refreshState() 164 testableLooper.processAllMessages() 165 166 assertThat(tile.state.forceExpandIcon).isTrue() 167 } 168 169 @Test testForceExpandIcon_durationNotAskAlways_falsenull170 fun testForceExpandIcon_durationNotAskAlways_false() { 171 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 172 173 tile.refreshState() 174 testableLooper.processAllMessages() 175 176 assertThat(tile.state.forceExpandIcon).isFalse() 177 } 178 179 @Test testForceExpandIcon_changeWhileListeningnull180 fun testForceExpandIcon_changeWhileListening() { 181 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 182 183 tile.refreshState() 184 testableLooper.processAllMessages() 185 186 assertThat(tile.state.forceExpandIcon).isFalse() 187 188 tile.handleSetListening(true) 189 190 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 191 testableLooper.processAllMessages() 192 193 assertThat(tile.state.forceExpandIcon).isTrue() 194 } 195 196 @Test testLaunchDialogFromViewWhenPromptnull197 fun testLaunchDialogFromViewWhenPrompt() { 198 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 199 200 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 201 testableLooper.processAllMessages() 202 203 tile.handleClick(expandable) 204 testableLooper.processAllMessages() 205 206 verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean()) 207 } 208 209 @Test testNoLaunchDialogWhenNotPromptnull210 fun testNoLaunchDialogWhenNotPrompt() { 211 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 212 213 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 214 testableLooper.processAllMessages() 215 216 tile.handleClick(expandable) 217 testableLooper.processAllMessages() 218 219 verify(mDialogTransitionAnimator, never()) 220 .showFromView(any(), any(), nullable(), anyBoolean()) 221 } 222 223 @Test testIcon_whenDndModeOff_isOffStatenull224 fun testIcon_whenDndModeOff_isOffState() { 225 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 226 val state = QSTile.BooleanState() 227 228 tile.handleUpdateState(state, /* arg= */ null) 229 230 assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_dnd_icon_off)) 231 } 232 233 @Test testIcon_whenDndModeOn_isOnStatenull234 fun testIcon_whenDndModeOn_isOnState() { 235 whenever(zenModeController.zen).thenReturn(ZEN_MODE_NO_INTERRUPTIONS) 236 val state = QSTile.BooleanState() 237 238 tile.handleUpdateState(state, /* arg= */ null) 239 240 assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_dnd_icon_on)) 241 } 242 createExpectedIconnull243 private fun createExpectedIcon(resId: Int): QSTile.Icon { 244 return if (isEnabled) { 245 DrawableIconWithRes(mContext.getDrawable(resId), resId) 246 } else { 247 QSTileImpl.ResourceIcon.get(resId) 248 } 249 } 250 } 251