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.provider.Settings 24 import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS 25 import android.provider.Settings.Global.ZEN_MODE_OFF 26 import android.testing.TestableLooper 27 import android.view.ContextThemeWrapper 28 import androidx.test.ext.junit.runners.AndroidJUnit4 29 import androidx.test.filters.SmallTest 30 import com.android.internal.logging.MetricsLogger 31 import com.android.systemui.res.R 32 import com.android.systemui.SysuiTestCase 33 import com.android.systemui.animation.DialogTransitionAnimator 34 import com.android.systemui.animation.Expandable 35 import com.android.systemui.classifier.FalsingManagerFake 36 import com.android.systemui.plugins.ActivityStarter 37 import com.android.systemui.plugins.qs.QSTile 38 import com.android.systemui.plugins.statusbar.StatusBarStateController 39 import com.android.systemui.qs.QSHost 40 import com.android.systemui.qs.QsEventLogger 41 import com.android.systemui.qs.logging.QSLogger 42 import com.android.systemui.qs.tileimpl.QSTileImpl 43 import com.android.systemui.statusbar.policy.ZenModeController 44 import com.android.systemui.util.mockito.any 45 import com.android.systemui.util.mockito.nullable 46 import com.android.systemui.util.settings.FakeSettings 47 import com.android.systemui.util.settings.SecureSettings 48 import com.google.common.truth.Truth.assertThat 49 import org.junit.After 50 import org.junit.Before 51 import org.junit.Test 52 import org.junit.runner.RunWith 53 import org.mockito.Mock 54 import org.mockito.Mockito.anyBoolean 55 import org.mockito.Mockito.never 56 import org.mockito.Mockito.verify 57 import org.mockito.MockitoAnnotations 58 import java.io.File 59 import org.mockito.Mockito.`when` as whenever 60 61 @SmallTest 62 @RunWith(AndroidJUnit4::class) 63 @TestableLooper.RunWithLooper(setAsMainLooper = true) 64 class DndTileTest : SysuiTestCase() { 65 66 companion object { 67 private const val DEFAULT_USER = 0 68 private const val KEY = Settings.Secure.ZEN_DURATION 69 } 70 71 @Mock 72 private lateinit var qsHost: QSHost 73 74 @Mock 75 private lateinit var metricsLogger: MetricsLogger 76 77 @Mock 78 private lateinit var statusBarStateController: StatusBarStateController 79 80 @Mock 81 private lateinit var activityStarter: ActivityStarter 82 83 @Mock 84 private lateinit var qsLogger: QSLogger 85 86 @Mock 87 private lateinit var uiEventLogger: QsEventLogger 88 89 @Mock 90 private lateinit var zenModeController: ZenModeController 91 92 @Mock 93 private lateinit var sharedPreferences: SharedPreferences 94 95 @Mock 96 private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator 97 98 @Mock 99 private lateinit var hostDialog: Dialog 100 101 @Mock 102 private lateinit var expandable: Expandable 103 104 @Mock 105 private lateinit var controller: DialogTransitionAnimator.Controller 106 107 private lateinit var secureSettings: SecureSettings 108 private lateinit var testableLooper: TestableLooper 109 private lateinit var tile: DndTile 110 111 @Before setUpnull112 fun setUp() { 113 MockitoAnnotations.initMocks(this) 114 testableLooper = TestableLooper.get(this) 115 secureSettings = FakeSettings() 116 117 whenever(qsHost.userId).thenReturn(DEFAULT_USER) 118 119 val wrappedContext = object : ContextWrapper( 120 ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings) 121 ) { 122 override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { 123 return sharedPreferences 124 } 125 } 126 whenever(qsHost.context).thenReturn(wrappedContext) 127 whenever(expandable.dialogTransitionController(any())).thenReturn(controller) 128 129 tile = DndTile( 130 qsHost, 131 uiEventLogger, 132 testableLooper.looper, 133 Handler(testableLooper.looper), 134 FalsingManagerFake(), 135 metricsLogger, 136 statusBarStateController, 137 activityStarter, 138 qsLogger, 139 zenModeController, 140 sharedPreferences, 141 secureSettings, 142 mDialogTransitionAnimator 143 ) 144 } 145 146 @After tearDownnull147 fun tearDown() { 148 tile.destroy() 149 testableLooper.processAllMessages() 150 } 151 152 @Test testForceExpandIcon_durationAskAlways_truenull153 fun testForceExpandIcon_durationAskAlways_true() { 154 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 155 156 tile.refreshState() 157 testableLooper.processAllMessages() 158 159 assertThat(tile.state.forceExpandIcon).isTrue() 160 } 161 162 @Test testForceExpandIcon_durationNotAskAlways_falsenull163 fun testForceExpandIcon_durationNotAskAlways_false() { 164 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 165 166 tile.refreshState() 167 testableLooper.processAllMessages() 168 169 assertThat(tile.state.forceExpandIcon).isFalse() 170 } 171 172 @Test testForceExpandIcon_changeWhileListeningnull173 fun testForceExpandIcon_changeWhileListening() { 174 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 175 176 tile.refreshState() 177 testableLooper.processAllMessages() 178 179 assertThat(tile.state.forceExpandIcon).isFalse() 180 181 tile.handleSetListening(true) 182 183 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 184 testableLooper.processAllMessages() 185 186 assertThat(tile.state.forceExpandIcon).isTrue() 187 } 188 189 @Test testLaunchDialogFromViewWhenPromptnull190 fun testLaunchDialogFromViewWhenPrompt() { 191 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 192 193 secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) 194 testableLooper.processAllMessages() 195 196 tile.handleClick(expandable) 197 testableLooper.processAllMessages() 198 199 verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean()) 200 } 201 202 @Test testNoLaunchDialogWhenNotPromptnull203 fun testNoLaunchDialogWhenNotPrompt() { 204 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 205 206 secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) 207 testableLooper.processAllMessages() 208 209 tile.handleClick(expandable) 210 testableLooper.processAllMessages() 211 212 verify(mDialogTransitionAnimator, never()) 213 .showFromView(any(), any(), nullable(), anyBoolean()) 214 } 215 216 @Test testIcon_whenDndModeOff_isOffStatenull217 fun testIcon_whenDndModeOff_isOffState() { 218 whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF) 219 val state = QSTile.BooleanState() 220 221 tile.handleUpdateState(state, /* arg= */ null) 222 223 assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_dnd_icon_off)) 224 } 225 226 @Test testIcon_whenDndModeOn_isOnStatenull227 fun testIcon_whenDndModeOn_isOnState() { 228 whenever(zenModeController.zen).thenReturn(ZEN_MODE_NO_INTERRUPTIONS) 229 val state = QSTile.BooleanState() 230 231 tile.handleUpdateState(state, /* arg= */ null) 232 233 assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_dnd_icon_on)) 234 } 235 } 236