• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.tileimpl
18 
19 import android.content.Context
20 import android.graphics.Rect
21 import android.graphics.drawable.Drawable
22 import android.service.quicksettings.Tile
23 import android.testing.TestableLooper
24 import android.text.TextUtils
25 import android.view.ContextThemeWrapper
26 import android.view.View
27 import android.view.accessibility.AccessibilityNodeInfo
28 import android.widget.Button
29 import android.widget.TextView
30 import androidx.test.ext.junit.runners.AndroidJUnit4
31 import androidx.test.filters.SmallTest
32 import com.android.systemui.SysuiTestCase
33 import com.android.systemui.haptics.qs.QSLongPressEffect
34 import com.android.systemui.haptics.qs.qsLongPressEffect
35 import com.android.systemui.plugins.qs.QSTile
36 import com.android.systemui.qs.qsTileFactory
37 import com.android.systemui.res.R
38 import com.android.systemui.testKosmos
39 import com.google.common.truth.Truth.assertThat
40 import org.junit.Before
41 import org.junit.Test
42 import org.junit.runner.RunWith
43 import org.mockito.Mock
44 import org.mockito.MockitoAnnotations
45 
46 @RunWith(AndroidJUnit4::class)
47 @SmallTest
48 @TestableLooper.RunWithLooper(setAsMainLooper = true)
49 class QSTileViewImplTest : SysuiTestCase() {
50 
51     @Mock private lateinit var customDrawable: Drawable
52 
53     private lateinit var tileView: FakeTileView
54     private lateinit var customDrawableView: View
55     private lateinit var chevronView: View
56     private val kosmos = testKosmos()
57 
58     @Before
setUpnull59     fun setUp() {
60         MockitoAnnotations.initMocks(this)
61         context.ensureTestableResources()
62 
63         tileView = FakeTileView(context, false, kosmos.qsLongPressEffect)
64         customDrawableView = tileView.requireViewById(R.id.customDrawable)
65         chevronView = tileView.requireViewById(R.id.chevron)
66     }
67 
68     @Test
testSecondaryLabelNotModified_unavailablenull69     fun testSecondaryLabelNotModified_unavailable() {
70         val state = QSTile.State()
71         val testString = "TEST STRING"
72         state.state = Tile.STATE_UNAVAILABLE
73         state.secondaryLabel = testString
74 
75         tileView.changeState(state)
76 
77         assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
78     }
79 
80     @Test
testSecondaryLabelNotModified_booleanInactivenull81     fun testSecondaryLabelNotModified_booleanInactive() {
82         val state = QSTile.BooleanState()
83         val testString = "TEST STRING"
84         state.state = Tile.STATE_INACTIVE
85         state.secondaryLabel = testString
86 
87         tileView.changeState(state)
88 
89         assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
90     }
91 
92     @Test
testSecondaryLabelNotModified_booleanActivenull93     fun testSecondaryLabelNotModified_booleanActive() {
94         val state = QSTile.BooleanState()
95         val testString = "TEST STRING"
96         state.state = Tile.STATE_ACTIVE
97         state.secondaryLabel = testString
98 
99         tileView.changeState(state)
100 
101         assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
102     }
103 
104     @Test
testSecondaryLabelNotModified_availableNotBoolean_inactivenull105     fun testSecondaryLabelNotModified_availableNotBoolean_inactive() {
106         val state = QSTile.State()
107         state.state = Tile.STATE_INACTIVE
108         state.secondaryLabel = ""
109 
110         tileView.changeState(state)
111 
112         assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
113     }
114 
115     @Test
testSecondaryLabelNotModified_availableNotBoolean_activenull116     fun testSecondaryLabelNotModified_availableNotBoolean_active() {
117         val state = QSTile.State()
118         state.state = Tile.STATE_ACTIVE
119         state.secondaryLabel = ""
120 
121         tileView.changeState(state)
122 
123         assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
124     }
125 
126     @Test
testSecondaryLabelDescription_unavailable_defaultnull127     fun testSecondaryLabelDescription_unavailable_default() {
128         val state = QSTile.State()
129         state.state = Tile.STATE_UNAVAILABLE
130         state.secondaryLabel = ""
131 
132         tileView.changeState(state)
133 
134         assertThat(state.secondaryLabel as CharSequence)
135             .isEqualTo(context.getString(R.string.tile_unavailable))
136     }
137 
138     @Test
testSecondaryLabelDescription_booleanInactive_defaultnull139     fun testSecondaryLabelDescription_booleanInactive_default() {
140         val state = QSTile.BooleanState()
141         state.state = Tile.STATE_INACTIVE
142         state.secondaryLabel = ""
143 
144         tileView.changeState(state)
145 
146         assertThat(state.secondaryLabel as CharSequence)
147             .isEqualTo(context.getString(R.string.switch_bar_off))
148     }
149 
150     @Test
testSecondaryLabelDescription_booleanActive_defaultnull151     fun testSecondaryLabelDescription_booleanActive_default() {
152         val state = QSTile.BooleanState()
153         state.state = Tile.STATE_ACTIVE
154         state.secondaryLabel = ""
155 
156         tileView.changeState(state)
157 
158         assertThat(state.secondaryLabel as CharSequence)
159             .isEqualTo(context.getString(R.string.switch_bar_on))
160     }
161 
162     @Test
testShowCustomDrawableViewBooleanStatenull163     fun testShowCustomDrawableViewBooleanState() {
164         val state = QSTile.BooleanState()
165         state.sideViewCustomDrawable = customDrawable
166 
167         tileView.changeState(state)
168 
169         assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE)
170         assertThat(chevronView.visibility).isEqualTo(View.GONE)
171     }
172 
173     @Test
testShowCustomDrawableViewNonBooleanStatenull174     fun testShowCustomDrawableViewNonBooleanState() {
175         val state = QSTile.State()
176         state.sideViewCustomDrawable = customDrawable
177 
178         tileView.changeState(state)
179 
180         assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE)
181         assertThat(chevronView.visibility).isEqualTo(View.GONE)
182     }
183 
184     @Test
testShowCustomDrawableViewBooleanStateForceChevronnull185     fun testShowCustomDrawableViewBooleanStateForceChevron() {
186         val state = QSTile.BooleanState()
187         state.sideViewCustomDrawable = customDrawable
188         state.forceExpandIcon = true
189 
190         tileView.changeState(state)
191 
192         assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE)
193         assertThat(chevronView.visibility).isEqualTo(View.GONE)
194     }
195 
196     @Test
testShowChevronNonBooleanStatenull197     fun testShowChevronNonBooleanState() {
198         val state = QSTile.State()
199 
200         tileView.changeState(state)
201 
202         assertThat(customDrawableView.visibility).isEqualTo(View.GONE)
203         assertThat(chevronView.visibility).isEqualTo(View.VISIBLE)
204     }
205 
206     @Test
testShowChevronBooleanStateForcheShownull207     fun testShowChevronBooleanStateForcheShow() {
208         val state = QSTile.BooleanState()
209         state.forceExpandIcon = true
210 
211         tileView.changeState(state)
212 
213         assertThat(customDrawableView.visibility).isEqualTo(View.GONE)
214         assertThat(chevronView.visibility).isEqualTo(View.VISIBLE)
215     }
216 
217     @Test
testNoImageShownnull218     fun testNoImageShown() {
219         val state = QSTile.BooleanState()
220 
221         tileView.changeState(state)
222 
223         assertThat(customDrawableView.visibility).isEqualTo(View.GONE)
224         assertThat(chevronView.visibility).isEqualTo(View.GONE)
225     }
226 
227     @Test
testUseStateStringsForKnownSpec_Booleannull228     fun testUseStateStringsForKnownSpec_Boolean() {
229         val state = QSTile.BooleanState()
230         val spec = "internet"
231         state.spec = spec
232 
233         val unavailableString = "${spec}_unavailable"
234         val offString = "${spec}_off"
235         val onString = "${spec}_on"
236 
237         context.orCreateTestableResources.addOverride(
238             R.array.tile_states_internet,
239             arrayOf(unavailableString, offString, onString),
240         )
241 
242         // State UNAVAILABLE
243         state.secondaryLabel = ""
244         state.state = Tile.STATE_UNAVAILABLE
245         tileView.changeState(state)
246         assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(unavailableString)
247 
248         // State INACTIVE
249         state.secondaryLabel = ""
250         state.state = Tile.STATE_INACTIVE
251         tileView.changeState(state)
252         assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(offString)
253 
254         // State ACTIVE
255         state.secondaryLabel = ""
256         state.state = Tile.STATE_ACTIVE
257         tileView.changeState(state)
258         assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(onString)
259     }
260 
261     @Test
testCollectionItemInfoHasPositionnull262     fun testCollectionItemInfoHasPosition() {
263         val position = 5
264         tileView.setPosition(position)
265 
266         val info = AccessibilityNodeInfo(tileView)
267         tileView.onInitializeAccessibilityNodeInfo(info)
268 
269         assertThat(info.collectionItemInfo.rowIndex).isEqualTo(position)
270         assertThat(info.collectionItemInfo.rowSpan).isEqualTo(1)
271         assertThat(info.collectionItemInfo.columnIndex).isEqualTo(0)
272         assertThat(info.collectionItemInfo.columnSpan).isEqualTo(1)
273     }
274 
275     @Test
testCollectionItemInfoNoPositionnull276     fun testCollectionItemInfoNoPosition() {
277         val info = AccessibilityNodeInfo(tileView)
278         tileView.onInitializeAccessibilityNodeInfo(info)
279 
280         assertThat(info.collectionItemInfo).isNull()
281     }
282 
283     @Test
testDisabledByPolicyInactive_usesUnavailableColorsnull284     fun testDisabledByPolicyInactive_usesUnavailableColors() {
285         val stateDisabledByPolicy = QSTile.State()
286         stateDisabledByPolicy.state = Tile.STATE_INACTIVE
287         stateDisabledByPolicy.disabledByPolicy = true
288 
289         val stateUnavailable = QSTile.State()
290         stateUnavailable.state = Tile.STATE_UNAVAILABLE
291 
292         tileView.changeState(stateDisabledByPolicy)
293         val colorsDisabledByPolicy = tileView.getCurrentColors()
294 
295         tileView.changeState(stateUnavailable)
296         val colorsUnavailable = tileView.getCurrentColors()
297 
298         assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
299     }
300 
301     @Test
testDisabledByPolicyActive_usesUnavailableColorsnull302     fun testDisabledByPolicyActive_usesUnavailableColors() {
303         val stateDisabledByPolicy = QSTile.State()
304         stateDisabledByPolicy.state = Tile.STATE_ACTIVE
305         stateDisabledByPolicy.disabledByPolicy = true
306 
307         val stateUnavailable = QSTile.State()
308         stateUnavailable.state = Tile.STATE_UNAVAILABLE
309 
310         tileView.changeState(stateDisabledByPolicy)
311         val colorsDisabledByPolicy = tileView.getCurrentColors()
312 
313         tileView.changeState(stateUnavailable)
314         val colorsUnavailable = tileView.getCurrentColors()
315 
316         assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
317     }
318 
319     @Test
testDisableByPolicyThenRemoved_changesColornull320     fun testDisableByPolicyThenRemoved_changesColor() {
321         val stateActive = QSTile.State()
322         stateActive.state = Tile.STATE_ACTIVE
323 
324         val stateDisabledByPolicy = stateActive.copy()
325         stateDisabledByPolicy.disabledByPolicy = true
326 
327         tileView.changeState(stateActive)
328         val activeColors = tileView.getCurrentColors()
329 
330         tileView.changeState(stateDisabledByPolicy)
331         // It has unavailable colors
332         assertThat(tileView.getCurrentColors()).isNotEqualTo(activeColors)
333 
334         // When we get back to not disabled by policy tile, it should go back to active colors
335         tileView.changeState(stateActive)
336         assertThat(tileView.getCurrentColors()).containsExactlyElementsIn(activeColors)
337     }
338 
339     @Test
testDisabledByPolicy_secondaryLabelTextnull340     fun testDisabledByPolicy_secondaryLabelText() {
341         val testA11yLabel = "TEST_LABEL"
342         context.orCreateTestableResources.addOverride(
343             R.string.accessibility_tile_disabled_by_policy_action_description,
344             testA11yLabel,
345         )
346 
347         val stateDisabledByPolicy = QSTile.State()
348         stateDisabledByPolicy.state = Tile.STATE_INACTIVE
349         stateDisabledByPolicy.disabledByPolicy = true
350 
351         tileView.changeState(stateDisabledByPolicy)
352 
353         val info = AccessibilityNodeInfo(tileView)
354         tileView.onInitializeAccessibilityNodeInfo(info)
355         assertThat(
356                 info.actionList
357                     .find { it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id }
358                     ?.label
359             )
360             .isEqualTo(testA11yLabel)
361     }
362 
363     @Test
testDisabledByPolicy_unavailableInStateDescriptionnull364     fun testDisabledByPolicy_unavailableInStateDescription() {
365         val state = QSTile.BooleanState()
366         val spec = "internet"
367         state.spec = spec
368         state.disabledByPolicy = true
369         state.state = Tile.STATE_INACTIVE
370 
371         val unavailableString = "${spec}_unavailable"
372         val offString = "${spec}_off"
373         val onString = "${spec}_on"
374 
375         context.orCreateTestableResources.addOverride(
376             R.array.tile_states_internet,
377             arrayOf(unavailableString, offString, onString),
378         )
379 
380         tileView.changeState(state)
381         assertThat(tileView.stateDescription?.contains(unavailableString)).isTrue()
382     }
383 
384     @Test
testNonSwitchA11yClass_longClickActionHasCorrectLabelnull385     fun testNonSwitchA11yClass_longClickActionHasCorrectLabel() {
386         val state =
387             QSTile.State().apply {
388                 expandedAccessibilityClassName = Button::class.java.name
389                 handlesLongClick = true
390             }
391         tileView.changeState(state)
392         val info = AccessibilityNodeInfo(tileView)
393         tileView.onInitializeAccessibilityNodeInfo(info)
394 
395         assertThat(
396                 info.actionList
397                     .find {
398                         it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id
399                     }
400                     ?.label
401             )
402             .isEqualTo(context.getString(R.string.accessibility_long_click_tile))
403     }
404 
405     @Test
testNonSwitchA11yClass_disabledByPolicy_noLongClickActionnull406     fun testNonSwitchA11yClass_disabledByPolicy_noLongClickAction() {
407         val state =
408             QSTile.State().apply {
409                 expandedAccessibilityClassName = Button::class.java.name
410                 handlesLongClick = true
411                 disabledByPolicy = true
412             }
413         tileView.changeState(state)
414         val info = AccessibilityNodeInfo(tileView)
415         tileView.onInitializeAccessibilityNodeInfo(info)
416 
417         assertThat(
418                 info.actionList.find {
419                     it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id
420                 }
421             )
422             .isNull()
423     }
424 
425     @Test
onStateChange_longPressEffectActive_withInvalidDuration_doesNotInitializeEffectnull426     fun onStateChange_longPressEffectActive_withInvalidDuration_doesNotInitializeEffect() {
427         val state = QSTile.State() // A state that handles longPress
428 
429         // GIVEN an invalid long-press effect duration
430         tileView.constantLongPressEffectDuration = -1
431 
432         // WHEN the state changes
433         tileView.changeState(state)
434 
435         // THEN the long-press effect is not initialized
436         assertThat(tileView.isLongPressEffectInitialized).isFalse()
437     }
438 
439     @Test
onStateChange_longPressEffectActive_withValidDuration_initializesEffectnull440     fun onStateChange_longPressEffectActive_withValidDuration_initializesEffect() {
441         // GIVEN a test state that handles long-press and a valid long-press effect duration
442         val state = QSTile.State()
443 
444         // WHEN the state changes
445         tileView.changeState(state)
446 
447         // THEN the long-press effect is initialized
448         assertThat(tileView.isLongPressEffectInitialized).isTrue()
449     }
450 
451     @Test
onStateChange_fromLongPress_to_noLongPress_clearsResourcesnull452     fun onStateChange_fromLongPress_to_noLongPress_clearsResources() {
453         // GIVEN a state that no longer handles long-press
454         val state = QSTile.State()
455         state.handlesLongClick = false
456 
457         // WHEN the state changes
458         tileView.changeState(state)
459 
460         // THEN the long-press effect resources are not set
461         assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
462     }
463 
464     @Test
onStateChange_fromNoLongPress_to_longPress_setsPropertiesnull465     fun onStateChange_fromNoLongPress_to_longPress_setsProperties() {
466         // GIVEN that the tile has changed to a state that does not handle long-press
467         val state = QSTile.State()
468         state.handlesLongClick = false
469         tileView.changeState(state)
470 
471         // WHEN the state changes back to handling long-press
472         state.handlesLongClick = true
473         tileView.changeState(state)
474 
475         // THEN the long-press effect resources are set
476         assertThat(tileView.areLongPressEffectPropertiesSet).isTrue()
477     }
478 
479     @Test
onStateChange_fromLongPress_toNoLongPress_whileLongPressRuns_doesNotClearResourcesnull480     fun onStateChange_fromLongPress_toNoLongPress_whileLongPressRuns_doesNotClearResources() {
481         // GIVEN that the long-press effect has been initialized
482         val state = QSTile.State()
483         state.handlesLongClick = true
484         tileView.changeState(state)
485 
486         // WHEN the long-press effect is running
487         kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.RUNNING_FORWARD)
488 
489         // WHEN a state changed happens so that the tile no longer handles long-press
490         state.handlesLongClick = false
491         tileView.changeState(state)
492 
493         // THEN the long-press effect resources are not cleared
494         assertThat(tileView.areLongPressEffectPropertiesSet).isTrue()
495     }
496 
497     @Test
onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverSetsPropertiesnull498     fun onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverSetsProperties() {
499         // GIVEN a tile where the long-press effect is null
500         tileView = FakeTileView(context, false, null)
501 
502         // GIVEN a state that no longer handles long-press
503         val state = QSTile.State()
504         state.handlesLongClick = false
505 
506         // WHEN the state changes
507         tileView.changeState(state)
508 
509         // THEN the effect properties are not set and the effect is not initialized
510         assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
511         assertThat(tileView.isLongPressEffectInitialized).isFalse()
512     }
513 
514     @Test
onStateChange_withoutLongPressEffect_fromNoLongPress_to_longPress_neverSetsPropertiesnull515     fun onStateChange_withoutLongPressEffect_fromNoLongPress_to_longPress_neverSetsProperties() {
516         // GIVEN a tile where the long-press effect is null
517         tileView = FakeTileView(context, false, null)
518 
519         // GIVEN that the tile has changed to a state that does not handle long-press
520         val state = QSTile.State()
521         state.handlesLongClick = false
522         tileView.changeState(state)
523 
524         // WHEN the state changes back to handling long-press
525         state.handlesLongClick = true
526         tileView.changeState(state)
527 
528         // THEN the effect properties are not set and the effect is not initialized
529         assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
530         assertThat(tileView.isLongPressEffectInitialized).isFalse()
531     }
532 
533     @Test
getPaddingForLaunchAnimation_onLongClickedState_paddingForLaunchAnimationIsConfigurednull534     fun getPaddingForLaunchAnimation_onLongClickedState_paddingForLaunchAnimationIsConfigured() {
535         val startingWidth = 100
536         val startingHeight = 50
537         val deltaWidth = (QSTileViewImpl.LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * startingWidth
538         val deltaHeight = (QSTileViewImpl.LONG_PRESS_EFFECT_HEIGHT_SCALE - 1f) * startingHeight
539 
540         // GIVEN that long-press effect properties are initialized
541         tileView.initializeLongPressProperties(startingHeight, startingWidth)
542 
543         // WHEN the long-press effect has ended in the long-click state
544         kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.LONG_CLICKED)
545 
546         // THE animation padding corresponds to the tile's growth due to the effect
547         val padding = tileView.getPaddingForLaunchAnimation()
548         assertThat(padding)
549             .isEqualTo(
550                 Rect(
551                     -deltaWidth.toInt() / 2,
552                     -deltaHeight.toInt() / 2,
553                     deltaWidth.toInt() / 2,
554                     deltaHeight.toInt() / 2,
555                 )
556             )
557     }
558 
559     @Test
getPaddingForLaunchAnimation_notInLongClickState_paddingForLaunchAnimationIsEmptynull560     fun getPaddingForLaunchAnimation_notInLongClickState_paddingForLaunchAnimationIsEmpty() {
561         val startingWidth = 100
562         val startingHeight = 50
563 
564         // GIVEN that long-press effect properties are initialized
565         tileView.initializeLongPressProperties(startingHeight, startingWidth)
566 
567         // WHEN the long-press effect has ended in the click state
568         kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.CLICKED)
569 
570         // THE animation padding is empty
571         val padding = tileView.getPaddingForLaunchAnimation()
572         assertThat(padding.isEmpty).isTrue()
573     }
574 
575     @Test
onActivityLaunchAnimationEnd_onFreshTile_longPressPropertiesAreResetnull576     fun onActivityLaunchAnimationEnd_onFreshTile_longPressPropertiesAreReset() {
577         // WHEN an activity launch animation ends on a fresh tile
578         tileView.onActivityLaunchAnimationEnd()
579 
580         // THEN the tile's long-press effect properties are reset by default
581         assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue()
582     }
583 
584     @Test
onUpdateLongPressEffectProperties_duringLongPressEffect_propertiesAreNotResetnull585     fun onUpdateLongPressEffectProperties_duringLongPressEffect_propertiesAreNotReset() {
586         // GIVEN a state that supports long-press
587         val state = QSTile.State()
588         tileView.changeState(state)
589 
590         // WHEN the long-press effect is updating the properties
591         tileView.updateLongPressEffectProperties(1f)
592 
593         // THEN the tile's long-press effect properties haven't reset
594         assertThat(tileView.haveLongPressPropertiesBeenReset).isFalse()
595     }
596 
597     @Test
onActivityLaunchAnimationEnd_afterLongPressEffect_longPressPropertiesAreResetnull598     fun onActivityLaunchAnimationEnd_afterLongPressEffect_longPressPropertiesAreReset() {
599         // GIVEN a state that supports long-press and the long-press effect updating
600         val state = QSTile.State()
601         tileView.changeState(state)
602         tileView.updateLongPressEffectProperties(1f)
603 
604         // WHEN an activity launch animation ends on a fresh tile
605         tileView.onActivityLaunchAnimationEnd()
606 
607         // THEN the tile's long-press effect properties are reset
608         assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue()
609     }
610 
611     @Test
onInit_withLongPressEffect_longPressEffectHasTileAndExpandablenull612     fun onInit_withLongPressEffect_longPressEffectHasTileAndExpandable() {
613         val tile = kosmos.qsTileFactory.createTile("Test Tile")
614         tileView.init(tile)
615 
616         assertThat(tileView.isTileAddedToLongPress).isTrue()
617         assertThat(tileView.isExpandableAddedToLongPress).isTrue()
618     }
619 
620     @Test
onInit_withoutLongPressEffect_longPressEffectDoesNotHaveTileAndExpandablenull621     fun onInit_withoutLongPressEffect_longPressEffectDoesNotHaveTileAndExpandable() {
622         tileView = FakeTileView(context, false, null)
623         val tile = kosmos.qsTileFactory.createTile("Test Tile")
624         tileView.init(tile)
625 
626         assertThat(tileView.isTileAddedToLongPress).isFalse()
627         assertThat(tileView.isExpandableAddedToLongPress).isFalse()
628     }
629 
630     class FakeTileView(
631         context: Context,
632         collapsed: Boolean,
633         private val longPressEffect: QSLongPressEffect?,
634     ) :
635         QSTileViewImpl(
636             ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings),
637             collapsed,
638             longPressEffect,
639         ) {
640         var constantLongPressEffectDuration = 500
641         val isTileAddedToLongPress: Boolean
642             get() = longPressEffect?.qsTile != null
643 
644         val isExpandableAddedToLongPress: Boolean
645             get() = longPressEffect?.expandable != null
646 
getLongPressEffectDurationnull647         override fun getLongPressEffectDuration(): Int = constantLongPressEffectDuration
648 
649         fun changeState(state: QSTile.State) {
650             handleStateChanged(state)
651         }
652     }
653 }
654