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