1 /* 2 * Copyright (C) 2018 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; 18 19 20 import static junit.framework.Assert.assertEquals; 21 import static junit.framework.Assert.assertFalse; 22 import static junit.framework.Assert.assertTrue; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.anyString; 27 import static org.mockito.ArgumentMatchers.isNull; 28 import static org.mockito.Mockito.clearInvocations; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.never; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.when; 33 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.SharedPreferences; 38 import android.database.ContentObserver; 39 import android.os.Handler; 40 import android.os.Looper; 41 import android.os.UserHandle; 42 import android.testing.AndroidTestingRunner; 43 import android.util.SparseArray; 44 import android.view.View; 45 46 import androidx.annotation.Nullable; 47 import androidx.test.filters.SmallTest; 48 49 import com.android.internal.logging.MetricsLogger; 50 import com.android.internal.util.CollectionUtils; 51 import com.android.systemui.R; 52 import com.android.systemui.SysuiTestCase; 53 import com.android.systemui.classifier.FalsingManagerFake; 54 import com.android.systemui.dump.nano.SystemUIProtoDump; 55 import com.android.systemui.flags.FakeFeatureFlags; 56 import com.android.systemui.flags.FeatureFlags; 57 import com.android.systemui.flags.Flags; 58 import com.android.systemui.plugins.ActivityStarter; 59 import com.android.systemui.plugins.PluginManager; 60 import com.android.systemui.plugins.qs.QSFactory; 61 import com.android.systemui.plugins.qs.QSTile; 62 import com.android.systemui.plugins.statusbar.StatusBarStateController; 63 import com.android.systemui.qs.external.CustomTile; 64 import com.android.systemui.qs.external.CustomTileStatePersister; 65 import com.android.systemui.qs.external.TileLifecycleManager; 66 import com.android.systemui.qs.external.TileServiceKey; 67 import com.android.systemui.qs.logging.QSLogger; 68 import com.android.systemui.qs.tileimpl.QSTileImpl; 69 import com.android.systemui.settings.UserFileManager; 70 import com.android.systemui.settings.UserTracker; 71 import com.android.systemui.shade.ShadeController; 72 import com.android.systemui.statusbar.phone.AutoTileManager; 73 import com.android.systemui.tuner.TunerService; 74 import com.android.systemui.util.FakeSharedPreferences; 75 import com.android.systemui.util.concurrency.FakeExecutor; 76 import com.android.systemui.util.settings.FakeSettings; 77 import com.android.systemui.util.settings.SecureSettings; 78 import com.android.systemui.util.time.FakeSystemClock; 79 80 import org.junit.Before; 81 import org.junit.Test; 82 import org.junit.runner.RunWith; 83 import org.mockito.Mock; 84 import org.mockito.MockitoAnnotations; 85 import org.mockito.stubbing.Answer; 86 87 import java.io.PrintWriter; 88 import java.io.StringWriter; 89 import java.util.List; 90 import java.util.concurrent.Executor; 91 92 import javax.inject.Provider; 93 94 @RunWith(AndroidTestingRunner.class) 95 @SmallTest 96 public class QSTileHostTest extends SysuiTestCase { 97 98 private static String MOCK_STATE_STRING = "MockState"; 99 private static ComponentName CUSTOM_TILE = 100 ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS"); 101 private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE); 102 private static final String SETTING = QSHost.TILES_SETTING; 103 104 @Mock 105 private QSFactory mDefaultFactory; 106 @Mock 107 private PluginManager mPluginManager; 108 @Mock 109 private TunerService mTunerService; 110 @Mock 111 private AutoTileManager mAutoTiles; 112 @Mock 113 private ShadeController mShadeController; 114 @Mock 115 private QSLogger mQSLogger; 116 @Mock 117 private CustomTile mCustomTile; 118 @Mock 119 private UserTracker mUserTracker; 120 private SecureSettings mSecureSettings; 121 @Mock 122 private CustomTileStatePersister mCustomTileStatePersister; 123 @Mock 124 private TileLifecycleManager.Factory mTileLifecycleManagerFactory; 125 @Mock 126 private TileLifecycleManager mTileLifecycleManager; 127 @Mock 128 private UserFileManager mUserFileManager; 129 130 private SparseArray<SharedPreferences> mSharedPreferencesByUser; 131 132 private FakeFeatureFlags mFeatureFlags; 133 134 private FakeExecutor mMainExecutor; 135 136 private QSTileHost mQSTileHost; 137 138 @Before setUp()139 public void setUp() { 140 MockitoAnnotations.initMocks(this); 141 mFeatureFlags = new FakeFeatureFlags(); 142 143 mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false); 144 mFeatureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, false); 145 146 mMainExecutor = new FakeExecutor(new FakeSystemClock()); 147 148 mSharedPreferencesByUser = new SparseArray<>(); 149 when(mTileLifecycleManagerFactory 150 .create(any(Intent.class), any(UserHandle.class))) 151 .thenReturn(mTileLifecycleManager); 152 when(mUserFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())) 153 .thenAnswer((Answer<SharedPreferences>) invocation -> { 154 assertEquals(QSTileHost.TILES, invocation.getArgument(0)); 155 int userId = invocation.getArgument(2); 156 if (!mSharedPreferencesByUser.contains(userId)) { 157 mSharedPreferencesByUser.put(userId, new FakeSharedPreferences()); 158 } 159 return mSharedPreferencesByUser.get(userId); 160 }); 161 162 mSecureSettings = new FakeSettings(); 163 saveSetting(""); 164 mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor, 165 mPluginManager, mTunerService, () -> mAutoTiles, mShadeController, 166 mQSLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, 167 mTileLifecycleManagerFactory, mUserFileManager, mFeatureFlags); 168 mMainExecutor.runAllReady(); 169 170 mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) { 171 @Override 172 public void onChange(boolean selfChange) { 173 super.onChange(selfChange); 174 mMainExecutor.execute(() -> mQSTileHost.onTuningChanged(SETTING, getSetting())); 175 mMainExecutor.runAllReady(); 176 } 177 }, mUserTracker.getUserId()); 178 setUpTileFactory(); 179 } 180 saveSetting(String value)181 private void saveSetting(String value) { 182 mSecureSettings.putStringForUser( 183 SETTING, value, "", false, mUserTracker.getUserId(), false); 184 } 185 getSetting()186 private String getSetting() { 187 return mSecureSettings.getStringForUser(SETTING, mUserTracker.getUserId()); 188 } 189 setUpTileFactory()190 private void setUpTileFactory() { 191 // Only create this kind of tiles 192 when(mDefaultFactory.createTile(anyString())).thenAnswer( 193 invocation -> { 194 String spec = invocation.getArgument(0); 195 if ("spec1".equals(spec)) { 196 return new TestTile1(mQSTileHost); 197 } else if ("spec2".equals(spec)) { 198 return new TestTile2(mQSTileHost); 199 } else if ("spec3".equals(spec)) { 200 return new TestTile3(mQSTileHost); 201 } else if ("na".equals(spec)) { 202 return new NotAvailableTile(mQSTileHost); 203 } else if (CUSTOM_TILE_SPEC.equals(spec)) { 204 QSTile tile = mCustomTile; 205 QSTile.State s = mock(QSTile.State.class); 206 s.spec = spec; 207 when(mCustomTile.getState()).thenReturn(s); 208 return tile; 209 } else if ("internet".equals(spec) 210 || "wifi".equals(spec) 211 || "cell".equals(spec)) { 212 return new TestTile1(mQSTileHost); 213 } else { 214 return null; 215 } 216 }); 217 when(mCustomTile.isAvailable()).thenReturn(true); 218 } 219 220 @Test testLoadTileSpecs_emptySetting()221 public void testLoadTileSpecs_emptySetting() { 222 List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); 223 assertFalse(tiles.isEmpty()); 224 } 225 226 @Test testLoadTileSpecs_nullSetting()227 public void testLoadTileSpecs_nullSetting() { 228 List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); 229 assertFalse(tiles.isEmpty()); 230 } 231 232 @Test testInvalidSpecUsesDefault()233 public void testInvalidSpecUsesDefault() { 234 mContext.getOrCreateTestableResources() 235 .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); 236 saveSetting("not-valid"); 237 238 assertEquals(2, mQSTileHost.getTiles().size()); 239 } 240 241 @Test testRemoveWifiAndCellularWithoutInternet()242 public void testRemoveWifiAndCellularWithoutInternet() { 243 saveSetting("wifi, spec1, cell, spec2"); 244 245 assertEquals("internet", mQSTileHost.getSpecs().get(0)); 246 assertEquals("spec1", mQSTileHost.getSpecs().get(1)); 247 assertEquals("spec2", mQSTileHost.getSpecs().get(2)); 248 } 249 250 @Test testRemoveWifiAndCellularWithInternet()251 public void testRemoveWifiAndCellularWithInternet() { 252 saveSetting("wifi, spec1, cell, spec2, internet"); 253 254 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 255 assertEquals("spec2", mQSTileHost.getSpecs().get(1)); 256 assertEquals("internet", mQSTileHost.getSpecs().get(2)); 257 } 258 259 @Test testRemoveWifiWithoutInternet()260 public void testRemoveWifiWithoutInternet() { 261 saveSetting("spec1, wifi, spec2"); 262 263 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 264 assertEquals("internet", mQSTileHost.getSpecs().get(1)); 265 assertEquals("spec2", mQSTileHost.getSpecs().get(2)); 266 } 267 268 @Test testRemoveCellWithInternet()269 public void testRemoveCellWithInternet() { 270 saveSetting("spec1, spec2, cell, internet"); 271 272 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 273 assertEquals("spec2", mQSTileHost.getSpecs().get(1)); 274 assertEquals("internet", mQSTileHost.getSpecs().get(2)); 275 } 276 277 @Test testNoWifiNoCellularNoInternet()278 public void testNoWifiNoCellularNoInternet() { 279 saveSetting("spec1,spec2"); 280 281 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 282 assertEquals("spec2", mQSTileHost.getSpecs().get(1)); 283 } 284 285 @Test testSpecWithInvalidDoesNotUseDefault()286 public void testSpecWithInvalidDoesNotUseDefault() { 287 mContext.getOrCreateTestableResources() 288 .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); 289 saveSetting("spec2,not-valid"); 290 291 assertEquals(1, mQSTileHost.getTiles().size()); 292 QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles()); 293 assertTrue(element instanceof TestTile2); 294 } 295 296 @Test testDump()297 public void testDump() { 298 saveSetting("spec1,spec2"); 299 StringWriter w = new StringWriter(); 300 PrintWriter pw = new PrintWriter(w); 301 mQSTileHost.dump(pw, new String[]{}); 302 303 String output = "QSTileHost:" + "\n" 304 + "tile specs: [spec1, spec2]" + "\n" 305 + "current user: 0" + "\n" 306 + "is dirty: false" + "\n" 307 + "tiles:" + "\n" 308 + "TestTile1:" + "\n" 309 + " MockState" + "\n" 310 + "TestTile2:" + "\n" 311 + " MockState" + "\n"; 312 313 System.out.println(output); 314 System.out.println(w.getBuffer().toString()); 315 316 assertEquals(output, w.getBuffer().toString()); 317 } 318 319 @Test testDefault()320 public void testDefault() { 321 mContext.getOrCreateTestableResources() 322 .addOverride(R.string.quick_settings_tiles_default, "spec1"); 323 saveSetting("default"); 324 assertEquals(1, mQSTileHost.getTiles().size()); 325 QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles()); 326 assertTrue(element instanceof TestTile1); 327 verify(mQSLogger).logTileAdded("spec1"); 328 } 329 330 @Test testNoRepeatedSpecs_addTile()331 public void testNoRepeatedSpecs_addTile() { 332 mContext.getOrCreateTestableResources() 333 .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); 334 saveSetting("spec1,spec2"); 335 336 mQSTileHost.addTile("spec1"); 337 338 assertEquals(2, mQSTileHost.getSpecs().size()); 339 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 340 assertEquals("spec2", mQSTileHost.getSpecs().get(1)); 341 } 342 343 @Test testAddTileAtValidPosition()344 public void testAddTileAtValidPosition() { 345 mContext.getOrCreateTestableResources() 346 .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); 347 saveSetting("spec1,spec3"); 348 349 mQSTileHost.addTile("spec2", 1); 350 mMainExecutor.runAllReady(); 351 352 assertEquals(3, mQSTileHost.getSpecs().size()); 353 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 354 assertEquals("spec2", mQSTileHost.getSpecs().get(1)); 355 assertEquals("spec3", mQSTileHost.getSpecs().get(2)); 356 } 357 358 @Test testAddTileAtInvalidPositionAddsToEnd()359 public void testAddTileAtInvalidPositionAddsToEnd() { 360 mContext.getOrCreateTestableResources() 361 .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); 362 saveSetting("spec1,spec3"); 363 364 mQSTileHost.addTile("spec2", 100); 365 mMainExecutor.runAllReady(); 366 367 assertEquals(3, mQSTileHost.getSpecs().size()); 368 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 369 assertEquals("spec3", mQSTileHost.getSpecs().get(1)); 370 assertEquals("spec2", mQSTileHost.getSpecs().get(2)); 371 } 372 373 @Test testAddTileAtEnd()374 public void testAddTileAtEnd() { 375 mContext.getOrCreateTestableResources() 376 .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); 377 saveSetting("spec1,spec3"); 378 379 mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END); 380 mMainExecutor.runAllReady(); 381 382 assertEquals(3, mQSTileHost.getSpecs().size()); 383 assertEquals("spec1", mQSTileHost.getSpecs().get(0)); 384 assertEquals("spec3", mQSTileHost.getSpecs().get(1)); 385 assertEquals("spec2", mQSTileHost.getSpecs().get(2)); 386 } 387 388 @Test testNoRepeatedSpecs_customTile()389 public void testNoRepeatedSpecs_customTile() { 390 saveSetting(CUSTOM_TILE_SPEC); 391 392 mQSTileHost.addTile(CUSTOM_TILE, /* end */ false); 393 mMainExecutor.runAllReady(); 394 395 assertEquals(1, mQSTileHost.getSpecs().size()); 396 assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0)); 397 } 398 399 @Test testAddedAtBeginningOnDefault_customTile()400 public void testAddedAtBeginningOnDefault_customTile() { 401 saveSetting("spec1"); // seed 402 403 mQSTileHost.addTile(CUSTOM_TILE); 404 mMainExecutor.runAllReady(); 405 406 assertEquals(2, mQSTileHost.getSpecs().size()); 407 assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0)); 408 } 409 410 @Test testAddedAtBeginning_customTile()411 public void testAddedAtBeginning_customTile() { 412 saveSetting("spec1"); // seed 413 414 mQSTileHost.addTile(CUSTOM_TILE, /* end */ false); 415 mMainExecutor.runAllReady(); 416 417 assertEquals(2, mQSTileHost.getSpecs().size()); 418 assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0)); 419 } 420 421 @Test testAddedAtEnd_customTile()422 public void testAddedAtEnd_customTile() { 423 saveSetting("spec1"); // seed 424 425 mQSTileHost.addTile(CUSTOM_TILE, /* end */ true); 426 mMainExecutor.runAllReady(); 427 428 assertEquals(2, mQSTileHost.getSpecs().size()); 429 assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(1)); 430 } 431 432 @Test testLoadTileSpec_repeated()433 public void testLoadTileSpec_repeated() { 434 List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); 435 436 assertEquals(2, specs.size()); 437 assertEquals("spec1", specs.get(0)); 438 assertEquals("spec2", specs.get(1)); 439 } 440 441 @Test testLoadTileSpec_repeatedInDefault()442 public void testLoadTileSpec_repeatedInDefault() { 443 mContext.getOrCreateTestableResources() 444 .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); 445 List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); 446 447 // Remove spurious tiles, like dbg:mem 448 specs.removeIf(spec -> !"spec1".equals(spec)); 449 assertEquals(1, specs.size()); 450 } 451 452 @Test testLoadTileSpec_repeatedDefaultAndSetting()453 public void testLoadTileSpec_repeatedDefaultAndSetting() { 454 mContext.getOrCreateTestableResources() 455 .addOverride(R.string.quick_settings_tiles_default, "spec1"); 456 List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); 457 458 // Remove spurious tiles, like dbg:mem 459 specs.removeIf(spec -> !"spec1".equals(spec)); 460 assertEquals(1, specs.size()); 461 } 462 463 @Test testNotAvailableTile_specNotNull()464 public void testNotAvailableTile_specNotNull() { 465 saveSetting("na"); 466 verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString()); 467 } 468 469 @Test testCustomTileRemoved_stateDeleted()470 public void testCustomTileRemoved_stateDeleted() { 471 mQSTileHost.changeTilesByUser(List.of(CUSTOM_TILE_SPEC), List.of()); 472 473 verify(mCustomTileStatePersister) 474 .removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId())); 475 } 476 477 @Test testRemoveTiles()478 public void testRemoveTiles() { 479 saveSetting("spec1,spec2,spec3"); 480 481 mQSTileHost.removeTiles(List.of("spec1", "spec2")); 482 483 mMainExecutor.runAllReady(); 484 assertEquals(List.of("spec3"), mQSTileHost.getSpecs()); 485 } 486 487 @Test testTilesRemovedInQuickSuccession()488 public void testTilesRemovedInQuickSuccession() { 489 saveSetting("spec1,spec2,spec3"); 490 mQSTileHost.removeTile("spec1"); 491 mQSTileHost.removeTile("spec3"); 492 493 mMainExecutor.runAllReady(); 494 assertEquals(List.of("spec2"), mQSTileHost.getSpecs()); 495 assertEquals("spec2", getSetting()); 496 } 497 498 @Test testAddTileInMainThread()499 public void testAddTileInMainThread() { 500 saveSetting("spec1,spec2"); 501 502 mQSTileHost.addTile("spec3"); 503 assertEquals(List.of("spec1", "spec2"), mQSTileHost.getSpecs()); 504 505 mMainExecutor.runAllReady(); 506 assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.getSpecs()); 507 } 508 509 @Test testRemoveTileInMainThread()510 public void testRemoveTileInMainThread() { 511 saveSetting("spec1,spec2"); 512 513 mQSTileHost.removeTile("spec1"); 514 assertEquals(List.of("spec1", "spec2"), mQSTileHost.getSpecs()); 515 516 mMainExecutor.runAllReady(); 517 assertEquals(List.of("spec2"), mQSTileHost.getSpecs()); 518 } 519 520 @Test testRemoveTilesInMainThread()521 public void testRemoveTilesInMainThread() { 522 saveSetting("spec1,spec2,spec3"); 523 524 mQSTileHost.removeTiles(List.of("spec3", "spec1")); 525 assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.getSpecs()); 526 527 mMainExecutor.runAllReady(); 528 assertEquals(List.of("spec2"), mQSTileHost.getSpecs()); 529 } 530 531 @Test testRemoveTileByUserInMainThread()532 public void testRemoveTileByUserInMainThread() { 533 saveSetting("spec1," + CUSTOM_TILE_SPEC); 534 535 mQSTileHost.removeTileByUser(CUSTOM_TILE); 536 assertEquals(List.of("spec1", CUSTOM_TILE_SPEC), mQSTileHost.getSpecs()); 537 538 mMainExecutor.runAllReady(); 539 assertEquals(List.of("spec1"), mQSTileHost.getSpecs()); 540 } 541 542 @Test testNonValidTileNotStoredInSettings()543 public void testNonValidTileNotStoredInSettings() { 544 saveSetting("spec1,not-valid"); 545 546 assertEquals(List.of("spec1"), mQSTileHost.getSpecs()); 547 assertEquals("spec1", getSetting()); 548 } 549 550 @Test testNotAvailableTileNotStoredInSettings()551 public void testNotAvailableTileNotStoredInSettings() { 552 saveSetting("spec1,na"); 553 554 assertEquals(List.of("spec1"), mQSTileHost.getSpecs()); 555 assertEquals("spec1", getSetting()); 556 } 557 558 @Test testIsTileAdded_true()559 public void testIsTileAdded_true() { 560 int user = mUserTracker.getUserId(); 561 getSharedPreferencesForUser(user) 562 .edit() 563 .putBoolean(CUSTOM_TILE.flattenToString(), true) 564 .apply(); 565 566 assertTrue(mQSTileHost.isTileAdded(CUSTOM_TILE, user)); 567 } 568 569 @Test testIsTileAdded_false()570 public void testIsTileAdded_false() { 571 int user = mUserTracker.getUserId(); 572 getSharedPreferencesForUser(user) 573 .edit() 574 .putBoolean(CUSTOM_TILE.flattenToString(), false) 575 .apply(); 576 577 assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user)); 578 } 579 580 @Test testIsTileAdded_notSet()581 public void testIsTileAdded_notSet() { 582 int user = mUserTracker.getUserId(); 583 584 assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user)); 585 } 586 587 @Test testIsTileAdded_differentUser()588 public void testIsTileAdded_differentUser() { 589 int user = mUserTracker.getUserId(); 590 mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user) 591 .edit() 592 .putBoolean(CUSTOM_TILE.flattenToString(), true) 593 .apply(); 594 595 assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user + 1)); 596 } 597 598 @Test testSetTileAdded_true()599 public void testSetTileAdded_true() { 600 int user = mUserTracker.getUserId(); 601 mQSTileHost.setTileAdded(CUSTOM_TILE, user, true); 602 603 assertTrue(getSharedPreferencesForUser(user) 604 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 605 } 606 607 @Test testSetTileAdded_false()608 public void testSetTileAdded_false() { 609 int user = mUserTracker.getUserId(); 610 mQSTileHost.setTileAdded(CUSTOM_TILE, user, false); 611 612 assertFalse(getSharedPreferencesForUser(user) 613 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 614 } 615 616 @Test testSetTileAdded_differentUser()617 public void testSetTileAdded_differentUser() { 618 int user = mUserTracker.getUserId(); 619 mQSTileHost.setTileAdded(CUSTOM_TILE, user, true); 620 621 assertFalse(getSharedPreferencesForUser(user + 1) 622 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 623 } 624 625 @Test testSetTileRemoved_afterCustomTileChangedByUser()626 public void testSetTileRemoved_afterCustomTileChangedByUser() { 627 int user = mUserTracker.getUserId(); 628 saveSetting(CUSTOM_TILE_SPEC); 629 630 // This will be done by TileServiceManager 631 mQSTileHost.setTileAdded(CUSTOM_TILE, user, true); 632 633 mQSTileHost.changeTilesByUser(mQSTileHost.getSpecs(), List.of("spec1")); 634 assertFalse(getSharedPreferencesForUser(user) 635 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 636 } 637 638 @Test testSetTileRemoved_removedByUser()639 public void testSetTileRemoved_removedByUser() { 640 int user = mUserTracker.getUserId(); 641 saveSetting(CUSTOM_TILE_SPEC); 642 643 // This will be done by TileServiceManager 644 mQSTileHost.setTileAdded(CUSTOM_TILE, user, true); 645 646 mQSTileHost.removeTileByUser(CUSTOM_TILE); 647 mMainExecutor.runAllReady(); 648 assertFalse(getSharedPreferencesForUser(user) 649 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 650 } 651 652 @Test testSetTileRemoved_removedBySystem()653 public void testSetTileRemoved_removedBySystem() { 654 int user = mUserTracker.getUserId(); 655 saveSetting("spec1," + CUSTOM_TILE_SPEC); 656 657 // This will be done by TileServiceManager 658 mQSTileHost.setTileAdded(CUSTOM_TILE, user, true); 659 660 mQSTileHost.removeTile(CUSTOM_TILE_SPEC); 661 mMainExecutor.runAllReady(); 662 assertFalse(getSharedPreferencesForUser(user) 663 .getBoolean(CUSTOM_TILE.flattenToString(), false)); 664 } 665 666 @Test testProtoDump_noTiles()667 public void testProtoDump_noTiles() { 668 SystemUIProtoDump proto = new SystemUIProtoDump(); 669 mQSTileHost.dumpProto(proto, new String[0]); 670 671 assertEquals(0, proto.tiles.length); 672 } 673 674 @Test testTilesInOrder()675 public void testTilesInOrder() { 676 saveSetting("spec1," + CUSTOM_TILE_SPEC); 677 678 SystemUIProtoDump proto = new SystemUIProtoDump(); 679 mQSTileHost.dumpProto(proto, new String[0]); 680 681 assertEquals(2, proto.tiles.length); 682 assertEquals("spec1", proto.tiles[0].getSpec()); 683 assertEquals(CUSTOM_TILE.getPackageName(), proto.tiles[1].getComponentName().packageName); 684 assertEquals(CUSTOM_TILE.getClassName(), proto.tiles[1].getComponentName().className); 685 } 686 687 @Test testUserChange_flagOn_autoTileManagerNotified()688 public void testUserChange_flagOn_autoTileManagerNotified() { 689 mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true); 690 int currentUser = mUserTracker.getUserId(); 691 clearInvocations(mAutoTiles); 692 when(mUserTracker.getUserId()).thenReturn(currentUser + 1); 693 694 mQSTileHost.onTuningChanged(SETTING, "a,b"); 695 verify(mAutoTiles).changeUser(UserHandle.of(currentUser + 1)); 696 } 697 getSharedPreferencesForUser(int user)698 private SharedPreferences getSharedPreferencesForUser(int user) { 699 return mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user); 700 } 701 702 private class TestQSTileHost extends QSTileHost { TestQSTileHost(Context context, QSFactory defaultFactory, Executor mainExecutor, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, ShadeController shadeController, QSLogger qsLogger, UserTracker userTracker, SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, TileLifecycleManager.Factory tileLifecycleManagerFactory, UserFileManager userFileManager, FeatureFlags featureFlags)703 TestQSTileHost(Context context, 704 QSFactory defaultFactory, Executor mainExecutor, 705 PluginManager pluginManager, TunerService tunerService, 706 Provider<AutoTileManager> autoTiles, 707 ShadeController shadeController, QSLogger qsLogger, 708 UserTracker userTracker, SecureSettings secureSettings, 709 CustomTileStatePersister customTileStatePersister, 710 TileLifecycleManager.Factory tileLifecycleManagerFactory, 711 UserFileManager userFileManager, FeatureFlags featureFlags) { 712 super(context, defaultFactory, mainExecutor, pluginManager, 713 tunerService, autoTiles, shadeController, qsLogger, 714 userTracker, secureSettings, customTileStatePersister, 715 tileLifecycleManagerFactory, userFileManager, featureFlags); 716 } 717 718 @Override onPluginConnected(QSFactory plugin, Context pluginContext)719 public void onPluginConnected(QSFactory plugin, Context pluginContext) { 720 } 721 722 @Override onPluginDisconnected(QSFactory plugin)723 public void onPluginDisconnected(QSFactory plugin) { 724 } 725 } 726 727 728 private class TestTile extends QSTileImpl<QSTile.State> { 729 TestTile(QSHost host)730 protected TestTile(QSHost host) { 731 super( 732 host, 733 mock(QsEventLogger.class), 734 mock(Looper.class), 735 mock(Handler.class), 736 new FalsingManagerFake(), 737 mock(MetricsLogger.class), 738 mock(StatusBarStateController.class), 739 mock(ActivityStarter.class), 740 QSTileHostTest.this.mQSLogger 741 ); 742 } 743 744 @Override newTileState()745 public State newTileState() { 746 State s = mock(QSTile.State.class); 747 when(s.toString()).thenReturn(MOCK_STATE_STRING); 748 return s; 749 } 750 751 @Override handleClick(@ullable View view)752 protected void handleClick(@Nullable View view) {} 753 754 @Override handleUpdateState(State state, Object arg)755 protected void handleUpdateState(State state, Object arg) {} 756 757 @Override getMetricsCategory()758 public int getMetricsCategory() { 759 return 0; 760 } 761 762 @Override getLongClickIntent()763 public Intent getLongClickIntent() { 764 return null; 765 } 766 767 @Override getTileLabel()768 public CharSequence getTileLabel() { 769 return null; 770 } 771 } 772 773 private class TestTile1 extends TestTile { 774 TestTile1(QSHost host)775 protected TestTile1(QSHost host) { 776 super(host); 777 } 778 } 779 780 private class TestTile2 extends TestTile { 781 TestTile2(QSHost host)782 protected TestTile2(QSHost host) { 783 super(host); 784 } 785 } 786 787 private class TestTile3 extends TestTile { 788 TestTile3(QSHost host)789 protected TestTile3(QSHost host) { 790 super(host); 791 } 792 } 793 794 private class NotAvailableTile extends TestTile { 795 NotAvailableTile(QSHost host)796 protected NotAvailableTile(QSHost host) { 797 super(host); 798 } 799 800 @Override isAvailable()801 public boolean isAvailable() { 802 return false; 803 } 804 } 805 } 806