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.drawable.Drawable 21 import android.service.quicksettings.Tile 22 import android.testing.AndroidTestingRunner 23 import android.testing.TestableLooper 24 import android.text.TextUtils 25 import android.view.View 26 import android.view.accessibility.AccessibilityNodeInfo 27 import android.widget.TextView 28 import androidx.test.filters.SmallTest 29 import com.android.systemui.R 30 import com.android.systemui.SysuiTestCase 31 import com.android.systemui.plugins.qs.QSIconView 32 import com.android.systemui.plugins.qs.QSTile 33 import com.google.common.truth.Truth.assertThat 34 import org.junit.Before 35 import org.junit.Test 36 import org.junit.runner.RunWith 37 import org.mockito.Mock 38 import org.mockito.MockitoAnnotations 39 40 @RunWith(AndroidTestingRunner::class) 41 @SmallTest 42 @TestableLooper.RunWithLooper(setAsMainLooper = true) 43 class QSTileViewImplTest : SysuiTestCase() { 44 45 @Mock 46 private lateinit var iconView: QSIconView 47 @Mock 48 private lateinit var customDrawable: Drawable 49 50 private lateinit var tileView: FakeTileView 51 private lateinit var customDrawableView: View 52 private lateinit var chevronView: View 53 54 @Before setUpnull55 fun setUp() { 56 MockitoAnnotations.initMocks(this) 57 context.ensureTestableResources() 58 59 tileView = FakeTileView(context, iconView, false) 60 customDrawableView = tileView.requireViewById(R.id.customDrawable) 61 chevronView = tileView.requireViewById(R.id.chevron) 62 } 63 64 @Test testSecondaryLabelNotModified_unavailablenull65 fun testSecondaryLabelNotModified_unavailable() { 66 val state = QSTile.State() 67 val testString = "TEST STRING" 68 state.state = Tile.STATE_UNAVAILABLE 69 state.secondaryLabel = testString 70 71 tileView.changeState(state) 72 73 assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString) 74 } 75 76 @Test testSecondaryLabelNotModified_booleanInactivenull77 fun testSecondaryLabelNotModified_booleanInactive() { 78 val state = QSTile.BooleanState() 79 val testString = "TEST STRING" 80 state.state = Tile.STATE_INACTIVE 81 state.secondaryLabel = testString 82 83 tileView.changeState(state) 84 85 assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString) 86 } 87 88 @Test testSecondaryLabelNotModified_booleanActivenull89 fun testSecondaryLabelNotModified_booleanActive() { 90 val state = QSTile.BooleanState() 91 val testString = "TEST STRING" 92 state.state = Tile.STATE_ACTIVE 93 state.secondaryLabel = testString 94 95 tileView.changeState(state) 96 97 assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString) 98 } 99 100 @Test testSecondaryLabelNotModified_availableNotBoolean_inactivenull101 fun testSecondaryLabelNotModified_availableNotBoolean_inactive() { 102 val state = QSTile.State() 103 state.state = Tile.STATE_INACTIVE 104 state.secondaryLabel = "" 105 106 tileView.changeState(state) 107 108 assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue() 109 } 110 111 @Test testSecondaryLabelNotModified_availableNotBoolean_activenull112 fun testSecondaryLabelNotModified_availableNotBoolean_active() { 113 val state = QSTile.State() 114 state.state = Tile.STATE_ACTIVE 115 state.secondaryLabel = "" 116 117 tileView.changeState(state) 118 119 assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue() 120 } 121 122 @Test testSecondaryLabelDescription_unavailable_defaultnull123 fun testSecondaryLabelDescription_unavailable_default() { 124 val state = QSTile.State() 125 state.state = Tile.STATE_UNAVAILABLE 126 state.secondaryLabel = "" 127 128 tileView.changeState(state) 129 130 assertThat(state.secondaryLabel as CharSequence).isEqualTo( 131 context.getString(R.string.tile_unavailable) 132 ) 133 } 134 135 @Test testSecondaryLabelDescription_booleanInactive_defaultnull136 fun testSecondaryLabelDescription_booleanInactive_default() { 137 val state = QSTile.BooleanState() 138 state.state = Tile.STATE_INACTIVE 139 state.secondaryLabel = "" 140 141 tileView.changeState(state) 142 143 assertThat(state.secondaryLabel as CharSequence).isEqualTo( 144 context.getString(R.string.switch_bar_off) 145 ) 146 } 147 148 @Test testSecondaryLabelDescription_booleanActive_defaultnull149 fun testSecondaryLabelDescription_booleanActive_default() { 150 val state = QSTile.BooleanState() 151 state.state = Tile.STATE_ACTIVE 152 state.secondaryLabel = "" 153 154 tileView.changeState(state) 155 156 assertThat(state.secondaryLabel as CharSequence).isEqualTo( 157 context.getString(R.string.switch_bar_on) 158 ) 159 } 160 161 @Test testShowCustomDrawableViewBooleanStatenull162 fun testShowCustomDrawableViewBooleanState() { 163 val state = QSTile.BooleanState() 164 state.sideViewCustomDrawable = customDrawable 165 166 tileView.changeState(state) 167 168 assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE) 169 assertThat(chevronView.visibility).isEqualTo(View.GONE) 170 } 171 172 @Test testShowCustomDrawableViewNonBooleanStatenull173 fun testShowCustomDrawableViewNonBooleanState() { 174 val state = QSTile.State() 175 state.sideViewCustomDrawable = customDrawable 176 177 tileView.changeState(state) 178 179 assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE) 180 assertThat(chevronView.visibility).isEqualTo(View.GONE) 181 } 182 183 @Test testShowCustomDrawableViewBooleanStateForceChevronnull184 fun testShowCustomDrawableViewBooleanStateForceChevron() { 185 val state = QSTile.BooleanState() 186 state.sideViewCustomDrawable = customDrawable 187 state.forceExpandIcon = true 188 189 tileView.changeState(state) 190 191 assertThat(customDrawableView.visibility).isEqualTo(View.VISIBLE) 192 assertThat(chevronView.visibility).isEqualTo(View.GONE) 193 } 194 195 @Test testShowChevronNonBooleanStatenull196 fun testShowChevronNonBooleanState() { 197 val state = QSTile.State() 198 199 tileView.changeState(state) 200 201 assertThat(customDrawableView.visibility).isEqualTo(View.GONE) 202 assertThat(chevronView.visibility).isEqualTo(View.VISIBLE) 203 } 204 205 @Test testShowChevronBooleanStateForcheShownull206 fun testShowChevronBooleanStateForcheShow() { 207 val state = QSTile.BooleanState() 208 state.forceExpandIcon = true 209 210 tileView.changeState(state) 211 212 assertThat(customDrawableView.visibility).isEqualTo(View.GONE) 213 assertThat(chevronView.visibility).isEqualTo(View.VISIBLE) 214 } 215 216 @Test testNoImageShownnull217 fun testNoImageShown() { 218 val state = QSTile.BooleanState() 219 220 tileView.changeState(state) 221 222 assertThat(customDrawableView.visibility).isEqualTo(View.GONE) 223 assertThat(chevronView.visibility).isEqualTo(View.GONE) 224 } 225 226 @Test testUseStateStringsForKnownSpec_Booleannull227 fun testUseStateStringsForKnownSpec_Boolean() { 228 val state = QSTile.BooleanState() 229 val spec = "internet" 230 state.spec = spec 231 232 val unavailableString = "${spec}_unavailable" 233 val offString = "${spec}_off" 234 val onString = "${spec}_on" 235 236 context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf( 237 unavailableString, 238 offString, 239 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 testDisabledByPolicy_secondaryLabelTextnull320 fun testDisabledByPolicy_secondaryLabelText() { 321 val testA11yLabel = "TEST_LABEL" 322 context.orCreateTestableResources 323 .addOverride( 324 R.string.accessibility_tile_disabled_by_policy_action_description, 325 testA11yLabel 326 ) 327 328 val stateDisabledByPolicy = QSTile.State() 329 stateDisabledByPolicy.state = Tile.STATE_INACTIVE 330 stateDisabledByPolicy.disabledByPolicy = true 331 332 tileView.changeState(stateDisabledByPolicy) 333 334 val info = AccessibilityNodeInfo(tileView) 335 tileView.onInitializeAccessibilityNodeInfo(info) 336 assertThat( 337 info.actionList.find { 338 it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id 339 }?.label 340 ).isEqualTo(testA11yLabel) 341 } 342 343 @Test testDisabledByPolicy_unavailableInStateDescriptionnull344 fun testDisabledByPolicy_unavailableInStateDescription() { 345 val state = QSTile.BooleanState() 346 val spec = "internet" 347 state.spec = spec 348 state.disabledByPolicy = true 349 state.state = Tile.STATE_INACTIVE 350 351 val unavailableString = "${spec}_unavailable" 352 val offString = "${spec}_off" 353 val onString = "${spec}_on" 354 355 context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf( 356 unavailableString, 357 offString, 358 onString 359 )) 360 361 tileView.changeState(state) 362 assertThat(tileView.stateDescription?.contains(unavailableString)).isTrue() 363 } 364 365 class FakeTileView( 366 context: Context, 367 icon: QSIconView, 368 collapsed: Boolean 369 ) : QSTileViewImpl(context, icon, collapsed) { changeStatenull370 fun changeState(state: QSTile.State) { 371 handleStateChanged(state) 372 } 373 } 374 } 375