• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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