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