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