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 18 package com.android.settings.slices; 19 20 import static android.content.ContentResolver.SCHEME_CONTENT; 21 import static android.content.pm.PackageManager.PERMISSION_DENIED; 22 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 23 import static android.content.res.Configuration.UI_MODE_NIGHT_NO; 24 import static android.content.res.Configuration.UI_MODE_NIGHT_YES; 25 26 import static com.google.common.truth.Truth.assertThat; 27 28 import static org.mockito.ArgumentMatchers.any; 29 import static org.mockito.ArgumentMatchers.anyInt; 30 import static org.mockito.ArgumentMatchers.anyString; 31 import static org.mockito.ArgumentMatchers.eq; 32 import static org.mockito.Mockito.doReturn; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.spy; 36 import static org.mockito.Mockito.verify; 37 import static org.mockito.Mockito.when; 38 39 import android.app.PendingIntent; 40 import android.app.slice.SliceManager; 41 import android.content.ContentResolver; 42 import android.content.Context; 43 import android.content.Intent; 44 import android.content.res.Resources.Theme; 45 import android.net.Uri; 46 import android.os.StrictMode; 47 import android.provider.Settings; 48 import android.provider.SettingsSlicesContract; 49 import android.util.ArraySet; 50 import android.view.accessibility.AccessibilityManager; 51 52 import androidx.slice.Slice; 53 import androidx.slice.SliceProvider; 54 import androidx.slice.widget.SliceLiveData; 55 56 import com.android.settings.Utils; 57 import com.android.settings.testutils.DatabaseTestUtils; 58 import com.android.settings.testutils.FakeToggleController; 59 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 60 import com.android.settings.testutils.shadow.ShadowLockPatternUtils; 61 import com.android.settings.testutils.shadow.ShadowThreadUtils; 62 import com.android.settings.testutils.shadow.ShadowUserManager; 63 import com.android.settings.testutils.shadow.ShadowUtils; 64 import com.android.settings.wifi.slice.WifiScanWorker; 65 import com.android.settingslib.wifi.WifiTracker; 66 67 import org.junit.After; 68 import org.junit.Before; 69 import org.junit.Ignore; 70 import org.junit.Test; 71 import org.junit.runner.RunWith; 72 import org.mockito.Mock; 73 import org.mockito.MockitoAnnotations; 74 import org.robolectric.Robolectric; 75 import org.robolectric.RobolectricTestRunner; 76 import org.robolectric.RuntimeEnvironment; 77 import org.robolectric.Shadows; 78 import org.robolectric.annotation.Config; 79 import org.robolectric.annotation.Implementation; 80 import org.robolectric.annotation.Implements; 81 import org.robolectric.annotation.Resetter; 82 import org.robolectric.shadow.api.Shadow; 83 import org.robolectric.shadows.ShadowAccessibilityManager; 84 import org.robolectric.shadows.ShadowBinder; 85 import org.robolectric.shadows.ShadowPackageManager; 86 87 import java.util.ArrayList; 88 import java.util.Arrays; 89 import java.util.Collection; 90 import java.util.Collections; 91 import java.util.HashMap; 92 import java.util.HashSet; 93 import java.util.List; 94 import java.util.Set; 95 96 /** 97 * TODO Investigate using ShadowContentResolver.registerProviderInternal(String, ContentProvider) 98 */ 99 @RunWith(RobolectricTestRunner.class) 100 @Config(shadows = {ShadowUserManager.class, ShadowUtils.class, 101 SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class, 102 ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class, 103 SettingsSliceProviderTest.ShadowWifiScanWorker.class, 104 SettingsSliceProviderTest.ShadowTheme.class}) 105 public class SettingsSliceProviderTest { 106 107 private static final String KEY = "KEY"; 108 private static final Uri INTENT_SLICE_URI = 109 new Uri.Builder().scheme(SCHEME_CONTENT) 110 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 111 .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT) 112 .appendPath(KEY) 113 .build(); 114 private static final Uri ACTION_SLICE_URI = 115 new Uri.Builder().scheme(SCHEME_CONTENT) 116 .authority(SettingsSlicesContract.AUTHORITY) 117 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 118 .appendPath(KEY) 119 .build(); 120 121 private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); 122 123 private Context mContext; 124 private SettingsSliceProvider mProvider; 125 private ShadowPackageManager mPackageManager; 126 @Mock 127 private SliceManager mManager; 128 129 private static final List<Uri> SPECIAL_CASE_PLATFORM_URIS = Arrays.asList( 130 CustomSliceRegistry.WIFI_SLICE_URI, 131 CustomSliceRegistry.BLUETOOTH_URI, 132 CustomSliceRegistry.LOCATION_SLICE_URI 133 ); 134 135 private static final List<Uri> SPECIAL_CASE_OEM_URIS = Arrays.asList( 136 CustomSliceRegistry.ZEN_MODE_SLICE_URI, 137 CustomSliceRegistry.FLASHLIGHT_SLICE_URI, 138 CustomSliceRegistry.MOBILE_DATA_SLICE_URI, 139 CustomSliceRegistry.WIFI_CALLING_URI 140 ); 141 142 @Before setUp()143 public void setUp() { 144 MockitoAnnotations.initMocks(this); 145 mContext = spy(RuntimeEnvironment.application); 146 // Register the fake a11y Service 147 ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract( 148 RuntimeEnvironment.application.getSystemService(AccessibilityManager.class)); 149 shadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>()); 150 151 mProvider = spy(new SettingsSliceProvider()); 152 ShadowStrictMode.reset(); 153 mProvider.mSliceWeakDataCache = new HashMap<>(); 154 mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext); 155 when(mProvider.getContext()).thenReturn(mContext); 156 157 SlicesDatabaseHelper.getInstance(mContext).setIndexedState(); 158 159 doReturn(mManager).when(mContext).getSystemService(SliceManager.class); 160 when(mManager.getPinnedSlices()).thenReturn(Collections.emptyList()); 161 162 mPackageManager = Shadows.shadowOf(mContext.getPackageManager()); 163 164 SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); 165 } 166 167 @After cleanUp()168 public void cleanUp() { 169 ShadowThreadUtils.reset(); 170 ShadowTheme.reset(); 171 DatabaseTestUtils.clearDb(mContext); 172 } 173 174 @Test 175 @Ignore testInitialSliceReturned_emptySlice()176 public void testInitialSliceReturned_emptySlice() { 177 SliceTestUtils.insertSliceToDb(mContext, KEY); 178 Slice slice = mProvider.onBindSlice(INTENT_SLICE_URI); 179 180 assertThat(slice.getUri()).isEqualTo(INTENT_SLICE_URI); 181 assertThat(slice.getItems()).isEmpty(); 182 } 183 184 @Test 185 @Ignore testLoadSlice_returnsSliceFromAccessor()186 public void testLoadSlice_returnsSliceFromAccessor() { 187 SliceTestUtils.insertSliceToDb(mContext, KEY); 188 189 mProvider.loadSlice(INTENT_SLICE_URI); 190 SliceData data = mProvider.mSliceWeakDataCache.get(INTENT_SLICE_URI); 191 192 assertThat(data.getKey()).isEqualTo(KEY); 193 assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); 194 } 195 196 @Test 197 @Ignore loadSlice_registersIntentFilter()198 public void loadSlice_registersIntentFilter() { 199 SliceTestUtils.insertSliceToDb(mContext, KEY); 200 201 mProvider.loadSlice(INTENT_SLICE_URI); 202 203 verify(mProvider) 204 .registerIntentToUri(eq(FakeToggleController.INTENT_FILTER), eq(INTENT_SLICE_URI)); 205 } 206 207 @Test 208 @Ignore loadSlice_registersBackgroundListener()209 public void loadSlice_registersBackgroundListener() { 210 SliceTestUtils.insertSliceToDb(mContext, KEY); 211 212 mProvider.loadSlice(INTENT_SLICE_URI); 213 214 Robolectric.flushForegroundThreadScheduler(); 215 Robolectric.flushBackgroundThreadScheduler(); 216 217 assertThat(mProvider.mPinnedWorkers.get(INTENT_SLICE_URI).getClass()) 218 .isEqualTo(FakeToggleController.TestWorker.class); 219 } 220 221 @Test 222 @Ignore testLoadSlice_cachedEntryRemovedOnBuild()223 public void testLoadSlice_cachedEntryRemovedOnBuild() { 224 SliceData data = getMockData(); 225 mProvider.mSliceWeakDataCache.put(data.getUri(), data); 226 mProvider.onBindSlice(data.getUri()); 227 SliceTestUtils.insertSliceToDb(mContext, data.getKey()); 228 229 SliceData cachedData = mProvider.mSliceWeakDataCache.get(data.getUri()); 230 231 assertThat(cachedData).isNull(); 232 } 233 234 @Test 235 @Ignore onBindSlice_mainThread_shouldNotOverrideStrictMode()236 public void onBindSlice_mainThread_shouldNotOverrideStrictMode() { 237 ShadowThreadUtils.setIsMainThread(true); 238 final StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy(); 239 SliceData data = getMockData(); 240 mProvider.mSliceWeakDataCache.put(data.getUri(), data); 241 mProvider.onBindSlice(data.getUri()); 242 243 final StrictMode.ThreadPolicy newThreadPolicy = StrictMode.getThreadPolicy(); 244 245 assertThat(newThreadPolicy.toString()).isEqualTo(oldThreadPolicy.toString()); 246 } 247 248 @Test 249 @Config(shadows = ShadowStrictMode.class) onBindSlice_backgroundThread_shouldOverrideStrictMode()250 public void onBindSlice_backgroundThread_shouldOverrideStrictMode() { 251 ShadowThreadUtils.setIsMainThread(false); 252 253 SliceData data = getMockData(); 254 mProvider.mSliceWeakDataCache.put(data.getUri(), data); 255 mProvider.onBindSlice(data.getUri()); 256 257 assertThat(ShadowStrictMode.isThreadPolicyOverridden()).isTrue(); 258 } 259 260 @Test onBindSlice_requestsBlockedSlice_returnsNull()261 public void onBindSlice_requestsBlockedSlice_returnsNull() { 262 final String blockedKey = "blocked_key"; 263 final Set<String> blockedSet = new ArraySet<>(); 264 blockedSet.add(blockedKey); 265 doReturn(blockedSet).when(mProvider).getBlockedKeys(); 266 final Uri blockedUri = new Uri.Builder() 267 .scheme(ContentResolver.SCHEME_CONTENT) 268 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 269 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 270 .appendPath(blockedKey) 271 .build(); 272 273 final Slice slice = mProvider.onBindSlice(blockedUri); 274 275 assertThat(slice).isNull(); 276 } 277 278 @Test 279 @Ignore onBindSlice_nightModeChanged_shouldReloadTheme()280 public void onBindSlice_nightModeChanged_shouldReloadTheme() { 281 mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_NO; 282 final SliceData data = getMockData(); 283 mProvider.mSliceWeakDataCache.put(data.getUri(), data); 284 mProvider.onBindSlice(data.getUri()); 285 286 mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_YES; 287 mProvider.onBindSlice(data.getUri()); 288 289 assertThat(ShadowTheme.isThemeRebased()).isTrue(); 290 } 291 292 @Test 293 @Ignore onBindSlice_nightModeNotChanged_shouldNotReloadTheme()294 public void onBindSlice_nightModeNotChanged_shouldNotReloadTheme() { 295 mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_NO; 296 SliceData data = getMockData(); 297 mProvider.mSliceWeakDataCache.put(data.getUri(), data); 298 mProvider.onBindSlice(data.getUri()); 299 300 mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_NO; 301 mProvider.onBindSlice(data.getUri()); 302 303 assertThat(ShadowTheme.isThemeRebased()).isFalse(); 304 } 305 306 @Test getDescendantUris_fullActionUri_returnsSelf()307 public void getDescendantUris_fullActionUri_returnsSelf() { 308 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(ACTION_SLICE_URI); 309 310 assertThat(descendants).containsExactly(ACTION_SLICE_URI); 311 } 312 313 @Test getDescendantUris_fullIntentUri_returnsSelf()314 public void getDescendantUris_fullIntentUri_returnsSelf() { 315 316 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(ACTION_SLICE_URI); 317 318 assertThat(descendants).containsExactly(ACTION_SLICE_URI); 319 } 320 321 @Test getDescendantUris_wrongPath_returnsEmpty()322 public void getDescendantUris_wrongPath_returnsEmpty() { 323 final Uri uri = new Uri.Builder() 324 .scheme(SCHEME_CONTENT) 325 .authority(SettingsSlicesContract.AUTHORITY) 326 .appendPath("invalid_path") 327 .build(); 328 329 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 330 331 assertThat(descendants).isEmpty(); 332 } 333 334 @Test 335 @Ignore getDescendantUris_invalidPath_returnsEmpty()336 public void getDescendantUris_invalidPath_returnsEmpty() { 337 final String key = "platform_key"; 338 SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, 339 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 340 final Uri uri = new Uri.Builder() 341 .scheme(SCHEME_CONTENT) 342 .authority(SettingsSlicesContract.AUTHORITY) 343 .appendPath("invalid") 344 .build(); 345 346 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 347 descendants.removeAll(SPECIAL_CASE_OEM_URIS); 348 349 assertThat(descendants).isEmpty(); 350 } 351 352 @Test 353 @Ignore getDescendantUris_platformSlice_doesNotReturnOEMSlice()354 public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() { 355 SliceTestUtils.insertSliceToDb(mContext, "oem_key", false /* isPlatformSlice */, 356 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 357 final Uri uri = new Uri.Builder() 358 .scheme(SCHEME_CONTENT) 359 .authority(SettingsSlicesContract.AUTHORITY) 360 .build(); 361 362 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 363 descendants.removeAll(SPECIAL_CASE_PLATFORM_URIS); 364 365 assertThat(descendants).isEmpty(); 366 } 367 368 @Test 369 @Ignore getDescendantUris_oemSlice_doesNotReturnPlatformSlice()370 public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() { 371 SliceTestUtils.insertSliceToDb(mContext, "platform_key", true /* isPlatformSlice */, 372 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 373 final Uri uri = new Uri.Builder() 374 .scheme(SCHEME_CONTENT) 375 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 376 .build(); 377 378 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 379 descendants.removeAll(SPECIAL_CASE_OEM_URIS); 380 381 assertThat(descendants).isEmpty(); 382 } 383 384 @Test 385 @Ignore getDescendantUris_oemSlice_returnsOEMUriDescendant()386 public void getDescendantUris_oemSlice_returnsOEMUriDescendant() { 387 final String key = "oem_key"; 388 SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */, 389 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 390 final Uri uri = new Uri.Builder() 391 .scheme(SCHEME_CONTENT) 392 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 393 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 394 .build(); 395 final Collection<Uri> expectedUris = new HashSet<>(); 396 expectedUris.addAll(SPECIAL_CASE_OEM_URIS); 397 expectedUris.add(new Uri.Builder() 398 .scheme(SCHEME_CONTENT) 399 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 400 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 401 .appendPath(key) 402 .build()); 403 404 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 405 406 assertThat(descendants).containsExactlyElementsIn(expectedUris); 407 } 408 409 @Test 410 @Ignore getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant()411 public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() { 412 final String key = "oem_key"; 413 SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */, 414 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 415 final Uri uri = new Uri.Builder() 416 .scheme(SCHEME_CONTENT) 417 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 418 .build(); 419 final Collection<Uri> expectedUris = new HashSet<>(); 420 expectedUris.addAll(SPECIAL_CASE_OEM_URIS); 421 expectedUris.add(new Uri.Builder() 422 .scheme(SCHEME_CONTENT) 423 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 424 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 425 .appendPath(key) 426 .build()); 427 428 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 429 430 assertThat(descendants).containsExactlyElementsIn(expectedUris); 431 } 432 433 @Test 434 @Ignore getDescendantUris_oemSliceNoPath_notContainPrivateUri()435 public void getDescendantUris_oemSliceNoPath_notContainPrivateUri() { 436 final String key = "oem_key"; 437 SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */, 438 null /* customizedUnavailableSliceSubtitle */, false /* isPublicSlice */); 439 final Uri uri = new Uri.Builder() 440 .scheme(SCHEME_CONTENT) 441 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 442 .build(); 443 final Uri expectedUri = new Uri.Builder() 444 .scheme(SCHEME_CONTENT) 445 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 446 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 447 .appendPath(key) 448 .build(); 449 450 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 451 452 assertThat(descendants).doesNotContain(expectedUri); 453 } 454 455 @Test 456 @Ignore getDescendantUris_platformSlice_returnsPlatformUriDescendant()457 public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() { 458 final String key = "platform_key"; 459 SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, 460 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 461 final Uri uri = new Uri.Builder() 462 .scheme(SCHEME_CONTENT) 463 .authority(SettingsSlicesContract.AUTHORITY) 464 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 465 .build(); 466 final Collection<Uri> expectedUris = new HashSet<>(); 467 expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); 468 expectedUris.add(new Uri.Builder() 469 .scheme(SCHEME_CONTENT) 470 .authority(SettingsSlicesContract.AUTHORITY) 471 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 472 .appendPath(key) 473 .build()); 474 475 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 476 477 assertThat(descendants).containsExactlyElementsIn(expectedUris); 478 } 479 480 @Test 481 @Ignore getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant()482 public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() { 483 final String key = "platform_key"; 484 SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, 485 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 486 final Uri uri = new Uri.Builder() 487 .scheme(SCHEME_CONTENT) 488 .authority(SettingsSlicesContract.AUTHORITY) 489 .build(); 490 final Collection<Uri> expectedUris = new HashSet<>(); 491 expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); 492 expectedUris.add(new Uri.Builder() 493 .scheme(SCHEME_CONTENT) 494 .authority(SettingsSlicesContract.AUTHORITY) 495 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 496 .appendPath(key) 497 .build()); 498 499 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 500 501 assertThat(descendants).containsExactlyElementsIn(expectedUris); 502 } 503 504 @Test 505 @Ignore getDescendantUris_noAuthorityNorPath_returnsAllUris()506 public void getDescendantUris_noAuthorityNorPath_returnsAllUris() { 507 final String platformKey = "platform_key"; 508 final String oemKey = "oemKey"; 509 SliceTestUtils.insertSliceToDb(mContext, platformKey, true /* isPlatformSlice */, 510 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 511 SliceTestUtils.insertSliceToDb(mContext, oemKey, false /* isPlatformSlice */, 512 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */); 513 final Uri uri = new Uri.Builder() 514 .scheme(SCHEME_CONTENT) 515 .build(); 516 final Collection<Uri> expectedUris = new HashSet<>(); 517 expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); 518 expectedUris.addAll(SPECIAL_CASE_OEM_URIS); 519 expectedUris.add(new Uri.Builder() 520 .scheme(SCHEME_CONTENT) 521 .authority(SettingsSlicesContract.AUTHORITY) 522 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 523 .appendPath(platformKey) 524 .build()); 525 expectedUris.add(new Uri.Builder() 526 .scheme(SCHEME_CONTENT) 527 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 528 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 529 .appendPath(oemKey) 530 .build()); 531 532 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri); 533 534 assertThat(descendants).containsExactlyElementsIn(expectedUris); 535 } 536 537 @Test 538 @Config(qualifiers = "mcc999") 539 @Ignore getDescendantUris_privateSlicesNeeded_containsPrivateSliceUri()540 public void getDescendantUris_privateSlicesNeeded_containsPrivateSliceUri() { 541 final String privateKey = "test_private"; 542 final Uri specialUri = Uri.parse("content://com.android.settings.slices/test"); 543 doReturn(true).when(mProvider).isPrivateSlicesNeeded(specialUri); 544 SliceTestUtils.insertSliceToDb(mContext, privateKey /* key */, false /* isPlatformSlice */, 545 null /* customizedUnavailableSliceSubtitle */, false /* isPublicSlice */); 546 final Collection<Uri> expectedUris = new HashSet<>(); 547 expectedUris.addAll(SPECIAL_CASE_OEM_URIS); 548 expectedUris.add(new Uri.Builder() 549 .scheme(SCHEME_CONTENT) 550 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 551 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 552 .appendPath(privateKey) 553 .build()); 554 555 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(specialUri); 556 557 assertThat(descendants).containsExactlyElementsIn(expectedUris); 558 } 559 560 @Test 561 @Config(qualifiers = "mcc999") 562 @Ignore getDescendantUris_privateSlicesNotNeeded_notContainPrivateSliceUri()563 public void getDescendantUris_privateSlicesNotNeeded_notContainPrivateSliceUri() { 564 final Uri specialUri = Uri.parse("content://com.android.settings.slices/test"); 565 doReturn(false).when(mProvider).isPrivateSlicesNeeded(specialUri); 566 SliceTestUtils.insertSliceToDb(mContext, 567 "test_private" /* key */, false /* isPlatformSlice */, 568 null /* customizedUnavailableSliceSubtitle */, false /* isPublicSlice */); 569 final Uri expectedUri = new Uri.Builder() 570 .scheme(SCHEME_CONTENT) 571 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 572 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 573 .appendPath("test_private") 574 .build(); 575 576 final Collection<Uri> descendants = mProvider.onGetSliceDescendants(specialUri); 577 578 assertThat(descendants).doesNotContain(expectedUri); 579 } 580 581 @Test onCreatePermissionRequest_returnsSettingIntent()582 public void onCreatePermissionRequest_returnsSettingIntent() { 583 final PendingIntent pendingIntent = mProvider.onCreatePermissionRequest( 584 CustomSliceRegistry.FLASHLIGHT_SLICE_URI, "com.android.whaaaat"); 585 final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS) 586 .setPackage(Utils.SETTINGS_PACKAGE_NAME); 587 PendingIntent settingsPendingIntent = 588 PendingIntent.getActivity(mContext, 0, settingsIntent, 589 PendingIntent.FLAG_IMMUTABLE); 590 591 assertThat(pendingIntent).isEqualTo(settingsPendingIntent); 592 } 593 594 @Test 595 @Ignore bindSlice_wifiSlice_returnsWifiSlice()596 public void bindSlice_wifiSlice_returnsWifiSlice() { 597 final Slice wifiSlice = mProvider.onBindSlice(CustomSliceRegistry.WIFI_SLICE_URI); 598 599 assertThat(wifiSlice.getUri()).isEqualTo(CustomSliceRegistry.WIFI_SLICE_URI); 600 } 601 602 @Test bindSlice_flashlightSlice_returnsFlashlightSlice()603 public void bindSlice_flashlightSlice_returnsFlashlightSlice() { 604 Settings.Secure.putInt( 605 mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1); 606 607 final Slice flashlightSlice = mProvider.onBindSlice( 608 CustomSliceRegistry.FLASHLIGHT_SLICE_URI); 609 610 assertThat(flashlightSlice.getUri()).isEqualTo(CustomSliceRegistry.FLASHLIGHT_SLICE_URI); 611 } 612 613 @Test onSlicePinned_noIntentRegistered_specialCaseUri_doesNotCrash()614 public void onSlicePinned_noIntentRegistered_specialCaseUri_doesNotCrash() { 615 final Uri uri = new Uri.Builder() 616 .scheme(ContentResolver.SCHEME_CONTENT) 617 .authority(SettingsSlicesContract.AUTHORITY) 618 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 619 .appendPath(SettingsSlicesContract.KEY_LOCATION) 620 .build(); 621 622 mProvider.onSlicePinned(uri); 623 } 624 625 @Test 626 @Ignore onSlicePinned_backgroundWorker_started()627 public void onSlicePinned_backgroundWorker_started() { 628 mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI); 629 630 verify(ShadowWifiScanWorker.getWifiTracker()).onStart(); 631 } 632 633 @Test 634 @Ignore onSlicePinned_backgroundWorker_stopped()635 public void onSlicePinned_backgroundWorker_stopped() { 636 mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI); 637 mProvider.onSliceUnpinned(CustomSliceRegistry.WIFI_SLICE_URI); 638 639 verify(ShadowWifiScanWorker.getWifiTracker()).onStop(); 640 } 641 642 @Test 643 @Ignore shutdown_backgroundWorker_closed()644 public void shutdown_backgroundWorker_closed() { 645 mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI); 646 mProvider.shutdown(); 647 648 verify(ShadowWifiScanWorker.getWifiTracker()).onDestroy(); 649 } 650 651 @Test 652 @Config(qualifiers = "mcc998") grantAllowlistedPackagePermissions_noAllowlist_shouldNotGrant()653 public void grantAllowlistedPackagePermissions_noAllowlist_shouldNotGrant() { 654 final List<Uri> uris = new ArrayList<>(); 655 uris.add(Uri.parse("content://settings/slice")); 656 657 SettingsSliceProvider.grantAllowlistedPackagePermissions(mContext, uris); 658 659 verify(mManager, never()).grantSlicePermission(anyString(), any(Uri.class)); 660 } 661 662 @Test 663 @Config(qualifiers = "mcc999") grantAllowlistedPackagePermissions_hasPackageAllowlist_shouldGrant()664 public void grantAllowlistedPackagePermissions_hasPackageAllowlist_shouldGrant() { 665 final List<Uri> uris = new ArrayList<>(); 666 uris.add(Uri.parse("content://settings/slice")); 667 668 SettingsSliceProvider.grantAllowlistedPackagePermissions(mContext, uris); 669 670 verify(mManager) 671 .grantSlicePermission("com.android.settings.slice_allowlist_package", uris.get(0)); 672 } 673 674 @Test 675 @Config(qualifiers = "mcc999") isPrivateSlicesNeeded_incorrectUri_returnFalse()676 public void isPrivateSlicesNeeded_incorrectUri_returnFalse() { 677 final Uri uri = Uri.parse("content://com.android.settings.slices/test123"); 678 679 assertThat(mProvider.isPrivateSlicesNeeded(uri)).isFalse(); 680 } 681 682 @Test isPrivateSlicesNeeded_noUri_returnFalse()683 public void isPrivateSlicesNeeded_noUri_returnFalse() { 684 final Uri uri = Uri.parse("content://com.android.settings.slices/test"); 685 686 assertThat(mProvider.isPrivateSlicesNeeded(uri)).isFalse(); 687 } 688 689 @Test 690 @Config(qualifiers = "mcc999") isPrivateSlicesNeeded_correctUriWithPermissionAndIsSI_returnTrue()691 public void isPrivateSlicesNeeded_correctUriWithPermissionAndIsSI_returnTrue() { 692 final Uri uri = Uri.parse("content://com.android.settings.slices/test"); 693 ShadowBinder.setCallingUid(123); 694 doReturn(PERMISSION_GRANTED) 695 .when(mContext).checkPermission(anyString(), anyInt(), anyInt()); 696 mPackageManager.setPackagesForUid(123, new String[]{"com.android.settings.intelligence"}); 697 698 assertThat(mProvider.isPrivateSlicesNeeded(uri)).isTrue(); 699 } 700 701 @Test 702 @Config(qualifiers = "mcc999") isPrivateSlicesNeeded_correctUriWithPermissionNotSI_returnFalse()703 public void isPrivateSlicesNeeded_correctUriWithPermissionNotSI_returnFalse() { 704 final Uri uri = Uri.parse("content://com.android.settings.slices/test"); 705 ShadowBinder.setCallingUid(123); 706 doReturn(PERMISSION_GRANTED) 707 .when(mContext).checkPermission(anyString(), anyInt(), anyInt()); 708 mPackageManager.setPackagesForUid(123, new String[]{"com.android.settings.test"}); 709 710 assertThat(mProvider.isPrivateSlicesNeeded(uri)).isFalse(); 711 } 712 713 @Test 714 @Config(qualifiers = "mcc999") isPrivateSlicesNeeded_correctUriNoPermission_returnFalse()715 public void isPrivateSlicesNeeded_correctUriNoPermission_returnFalse() { 716 final Uri uri = Uri.parse("content://com.android.settings.slices/test"); 717 ShadowBinder.setCallingUid(123); 718 doReturn(PERMISSION_DENIED).when(mContext).checkPermission(anyString(), anyInt(), anyInt()); 719 mPackageManager.setPackagesForUid(123, new String[]{"com.android.settings.intelligence"}); 720 721 assertThat(mProvider.isPrivateSlicesNeeded(uri)).isFalse(); 722 } 723 getMockData()724 private static SliceData getMockData() { 725 return new SliceData.Builder() 726 .setKey(KEY) 727 .setUri(URI) 728 .setTitle(SliceTestUtils.FAKE_TITLE) 729 .setSummary(SliceTestUtils.FAKE_SUMMARY) 730 .setScreenTitle(SliceTestUtils.FAKE_SCREEN_TITLE) 731 .setIcon(SliceTestUtils.FAKE_ICON) 732 .setFragmentName(SliceTestUtils.FAKE_FRAGMENT_NAME) 733 .setPreferenceControllerClassName(SliceTestUtils.FAKE_CONTROLLER_NAME) 734 .setHighlightMenuRes(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES) 735 .build(); 736 } 737 738 @Implements(WifiScanWorker.class) 739 public static class ShadowWifiScanWorker { 740 private static WifiTracker mWifiTracker; 741 742 @Implementation onSlicePinned()743 protected void onSlicePinned() { 744 mWifiTracker = mock(WifiTracker.class); 745 mWifiTracker.onStart(); 746 } 747 748 @Implementation onSliceUnpinned()749 protected void onSliceUnpinned() { 750 mWifiTracker.onStop(); 751 } 752 753 @Implementation close()754 protected void close() { 755 mWifiTracker.onDestroy(); 756 } 757 getWifiTracker()758 static WifiTracker getWifiTracker() { 759 return mWifiTracker; 760 } 761 } 762 763 @Implements(value = StrictMode.class) 764 public static class ShadowStrictMode { 765 766 private static int sSetThreadPolicyCount; 767 768 @Resetter reset()769 public static void reset() { 770 sSetThreadPolicyCount = 0; 771 } 772 773 @Implementation setThreadPolicy(final StrictMode.ThreadPolicy policy)774 protected static void setThreadPolicy(final StrictMode.ThreadPolicy policy) { 775 sSetThreadPolicyCount++; 776 } 777 isThreadPolicyOverridden()778 private static boolean isThreadPolicyOverridden() { 779 return sSetThreadPolicyCount != 0; 780 } 781 } 782 783 @Implements(Theme.class) 784 public static class ShadowTheme { 785 private static boolean sThemeRebased; 786 787 @Resetter reset()788 public static void reset() { 789 sThemeRebased = false; 790 } 791 792 @Implementation rebase()793 public void rebase() { 794 sThemeRebased = true; 795 } 796 isThemeRebased()797 static boolean isThemeRebased() { 798 return sThemeRebased; 799 } 800 } 801 } 802