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 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.doReturn;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.PendingIntent;
35 import android.app.slice.SliceManager;
36 import android.content.ContentResolver;
37 import android.content.ContentValues;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.database.sqlite.SQLiteDatabase;
41 import android.net.Uri;
42 import android.os.StrictMode;
43 import android.provider.Settings;
44 import android.provider.SettingsSlicesContract;
45 import android.util.ArraySet;
46 import android.view.accessibility.AccessibilityManager;
47 
48 import androidx.slice.Slice;
49 import androidx.slice.SliceProvider;
50 import androidx.slice.widget.SliceLiveData;
51 
52 import com.android.settings.R;
53 import com.android.settings.Utils;
54 import com.android.settings.testutils.DatabaseTestUtils;
55 import com.android.settings.testutils.FakeToggleController;
56 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
57 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
58 import com.android.settings.testutils.shadow.ShadowThreadUtils;
59 import com.android.settings.testutils.shadow.ShadowUserManager;
60 import com.android.settings.testutils.shadow.ShadowUtils;
61 import com.android.settings.wifi.slice.WifiScanWorker;
62 import com.android.settingslib.wifi.WifiTracker;
63 
64 import org.junit.After;
65 import org.junit.Before;
66 import org.junit.Test;
67 import org.junit.runner.RunWith;
68 import org.mockito.Mock;
69 import org.mockito.MockitoAnnotations;
70 import org.robolectric.Robolectric;
71 import org.robolectric.RobolectricTestRunner;
72 import org.robolectric.RuntimeEnvironment;
73 import org.robolectric.annotation.Config;
74 import org.robolectric.annotation.Implementation;
75 import org.robolectric.annotation.Implements;
76 import org.robolectric.annotation.Resetter;
77 import org.robolectric.shadow.api.Shadow;
78 import org.robolectric.shadows.ShadowAccessibilityManager;
79 
80 import java.util.ArrayList;
81 import java.util.Arrays;
82 import java.util.Collection;
83 import java.util.Collections;
84 import java.util.HashMap;
85 import java.util.HashSet;
86 import java.util.List;
87 import java.util.Set;
88 
89 /**
90  * TODO Investigate using ShadowContentResolver.registerProviderInternal(String, ContentProvider)
91  */
92 @RunWith(RobolectricTestRunner.class)
93 @Config(shadows = {ShadowUserManager.class, ShadowThreadUtils.class, ShadowUtils.class,
94         SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
95         ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class,
96         SettingsSliceProviderTest.ShadowWifiScanWorker.class})
97 public class SettingsSliceProviderTest {
98 
99     private static final String KEY = "KEY";
100     private static final String INTENT_PATH =
101             SettingsSlicesContract.PATH_SETTING_INTENT + "/" + KEY;
102     private static final String TITLE = "title";
103     private static final String SUMMARY = "summary";
104     private static final String SCREEN_TITLE = "screen title";
105     private static final String FRAGMENT_NAME = "fragment name";
106     private static final int ICON = R.drawable.ic_settings_accent;
107     private static final Uri URI = Uri.parse("content://com.android.settings.slices/test");
108     private static final String PREF_CONTROLLER = FakeToggleController.class.getName();
109 
110     private Context mContext;
111     private SettingsSliceProvider mProvider;
112     @Mock
113     private SliceManager mManager;
114 
115     private static final List<Uri> SPECIAL_CASE_PLATFORM_URIS = Arrays.asList(
116             CustomSliceRegistry.WIFI_SLICE_URI,
117             CustomSliceRegistry.BLUETOOTH_URI,
118             CustomSliceRegistry.LOCATION_SLICE_URI
119     );
120 
121     private static final List<Uri> SPECIAL_CASE_OEM_URIS = Arrays.asList(
122             CustomSliceRegistry.ZEN_MODE_SLICE_URI,
123             CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
124             CustomSliceRegistry.MOBILE_DATA_SLICE_URI
125     );
126 
127     @Before
setUp()128     public void setUp() {
129         MockitoAnnotations.initMocks(this);
130         mContext = spy(RuntimeEnvironment.application);
131         // Register the fake a11y Service
132         ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
133                 RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
134         shadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
135 
136         mProvider = spy(new SettingsSliceProvider());
137         ShadowStrictMode.reset();
138         mProvider.mSliceWeakDataCache = new HashMap<>();
139         mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
140         when(mProvider.getContext()).thenReturn(mContext);
141 
142         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
143 
144         doReturn(mManager).when(mContext).getSystemService(SliceManager.class);
145         when(mManager.getPinnedSlices()).thenReturn(Collections.emptyList());
146 
147         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
148     }
149 
150     @After
cleanUp()151     public void cleanUp() {
152         ShadowThreadUtils.reset();
153         DatabaseTestUtils.clearDb(mContext);
154     }
155 
156     @Test
testInitialSliceReturned_emptySlice()157     public void testInitialSliceReturned_emptySlice() {
158         insertSpecialCase(KEY);
159         final Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
160         Slice slice = mProvider.onBindSlice(uri);
161 
162         assertThat(slice.getUri()).isEqualTo(uri);
163         assertThat(slice.getItems()).isEmpty();
164     }
165 
166     @Test
testLoadSlice_returnsSliceFromAccessor()167     public void testLoadSlice_returnsSliceFromAccessor() {
168         insertSpecialCase(KEY);
169         final Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
170 
171         mProvider.loadSlice(uri);
172         SliceData data = mProvider.mSliceWeakDataCache.get(uri);
173 
174         assertThat(data.getKey()).isEqualTo(KEY);
175         assertThat(data.getTitle()).isEqualTo(TITLE);
176     }
177 
178     @Test
loadSlice_registersIntentFilter()179     public void loadSlice_registersIntentFilter() {
180         insertSpecialCase(KEY);
181         final Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
182 
183         mProvider.loadSlice(uri);
184 
185         verify(mProvider).registerIntentToUri(eq(FakeToggleController.INTENT_FILTER), eq(uri));
186     }
187 
188     @Test
loadSlice_registersBackgroundListener()189     public void loadSlice_registersBackgroundListener() {
190         insertSpecialCase(KEY);
191         final Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
192 
193         mProvider.loadSlice(uri);
194 
195         Robolectric.flushForegroundThreadScheduler();
196         Robolectric.flushBackgroundThreadScheduler();
197 
198         assertThat(mProvider.mPinnedWorkers.get(uri).getClass())
199                 .isEqualTo(FakeToggleController.TestWorker.class);
200     }
201 
202     @Test
testLoadSlice_cachedEntryRemovedOnBuild()203     public void testLoadSlice_cachedEntryRemovedOnBuild() {
204         SliceData data = getDummyData();
205         mProvider.mSliceWeakDataCache.put(data.getUri(), data);
206         mProvider.onBindSlice(data.getUri());
207         insertSpecialCase(data.getKey());
208 
209         SliceData cachedData = mProvider.mSliceWeakDataCache.get(data.getUri());
210 
211         assertThat(cachedData).isNull();
212     }
213 
214     @Test
onBindSlice_mainThread_shouldNotOverrideStrictMode()215     public void onBindSlice_mainThread_shouldNotOverrideStrictMode() {
216         ShadowThreadUtils.setIsMainThread(true);
217         final StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
218         SliceData data = getDummyData();
219         mProvider.mSliceWeakDataCache.put(data.getUri(), data);
220         mProvider.onBindSlice(data.getUri());
221 
222         final StrictMode.ThreadPolicy newThreadPolicy = StrictMode.getThreadPolicy();
223 
224         assertThat(newThreadPolicy.toString()).isEqualTo(oldThreadPolicy.toString());
225     }
226 
227     @Test
228     @Config(shadows = ShadowStrictMode.class)
onBindSlice_backgroundThread_shouldOverrideStrictMode()229     public void onBindSlice_backgroundThread_shouldOverrideStrictMode() {
230         ShadowThreadUtils.setIsMainThread(false);
231 
232         SliceData data = getDummyData();
233         mProvider.mSliceWeakDataCache.put(data.getUri(), data);
234         mProvider.onBindSlice(data.getUri());
235 
236         assertThat(ShadowStrictMode.isThreadPolicyOverridden()).isTrue();
237     }
238 
239     @Test
onBindSlice_requestsBlockedSlice_returnsNull()240     public void onBindSlice_requestsBlockedSlice_returnsNull() {
241         final String blockedKey = "blocked_key";
242         final Set<String> blockedSet = new ArraySet<>();
243         blockedSet.add(blockedKey);
244         doReturn(blockedSet).when(mProvider).getBlockedKeys();
245         final Uri blockedUri = new Uri.Builder()
246                 .scheme(ContentResolver.SCHEME_CONTENT)
247                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
248                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
249                 .appendPath(blockedKey)
250                 .build();
251 
252         final Slice slice = mProvider.onBindSlice(blockedUri);
253 
254         assertThat(slice).isNull();
255     }
256 
257     @Test
getDescendantUris_fullActionUri_returnsSelf()258     public void getDescendantUris_fullActionUri_returnsSelf() {
259         final Uri uri = SliceBuilderUtils.getUri(
260                 SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
261 
262         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
263 
264         assertThat(descendants).containsExactly(uri);
265     }
266 
267     @Test
getDescendantUris_fullIntentUri_returnsSelf()268     public void getDescendantUris_fullIntentUri_returnsSelf() {
269         final Uri uri = SliceBuilderUtils.getUri(
270                 SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
271 
272         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
273 
274         assertThat(descendants).containsExactly(uri);
275     }
276 
277     @Test
getDescendantUris_wrongPath_returnsEmpty()278     public void getDescendantUris_wrongPath_returnsEmpty() {
279         final Uri uri = SliceBuilderUtils.getUri("invalid_path", true);
280 
281         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
282 
283         assertThat(descendants).isEmpty();
284     }
285 
286     @Test
getDescendantUris_invalidPath_returnsEmpty()287     public void getDescendantUris_invalidPath_returnsEmpty() {
288         final String key = "platform_key";
289         insertSpecialCase(key, true /* isPlatformSlice */);
290         final Uri uri = new Uri.Builder()
291                 .scheme(SCHEME_CONTENT)
292                 .authority(SettingsSlicesContract.AUTHORITY)
293                 .appendPath("invalid")
294                 .build();
295 
296         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
297         descendants.removeAll(SPECIAL_CASE_OEM_URIS);
298 
299         assertThat(descendants).isEmpty();
300     }
301 
302     @Test
getDescendantUris_platformSlice_doesNotReturnOEMSlice()303     public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
304         insertSpecialCase("oem_key", false /* isPlatformSlice */);
305         final Uri uri = new Uri.Builder()
306                 .scheme(SCHEME_CONTENT)
307                 .authority(SettingsSlicesContract.AUTHORITY)
308                 .build();
309 
310         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
311         descendants.removeAll(SPECIAL_CASE_PLATFORM_URIS);
312 
313         assertThat(descendants).isEmpty();
314     }
315 
316     @Test
getDescendantUris_oemSlice_doesNotReturnPlatformSlice()317     public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
318         insertSpecialCase("platform_key", true /* isPlatformSlice */);
319         final Uri uri = new Uri.Builder()
320                 .scheme(SCHEME_CONTENT)
321                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
322                 .build();
323 
324         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
325         descendants.removeAll(SPECIAL_CASE_OEM_URIS);
326 
327         assertThat(descendants).isEmpty();
328     }
329 
330     @Test
getDescendantUris_oemSlice_returnsOEMUriDescendant()331     public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
332         final String key = "oem_key";
333         insertSpecialCase(key, false /* isPlatformSlice */);
334         final Uri uri = new Uri.Builder()
335                 .scheme(SCHEME_CONTENT)
336                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
337                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
338                 .build();
339         final Collection<Uri> expectedUris = new HashSet<>();
340         expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
341         expectedUris.add(new Uri.Builder()
342                 .scheme(SCHEME_CONTENT)
343                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
344                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
345                 .appendPath(key)
346                 .build());
347 
348         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
349 
350         assertThat(descendants).containsExactlyElementsIn(expectedUris);
351     }
352 
353     @Test
getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant()354     public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() {
355         final String key = "oem_key";
356         insertSpecialCase(key, false /* isPlatformSlice */);
357         final Uri uri = new Uri.Builder()
358                 .scheme(SCHEME_CONTENT)
359                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
360                 .build();
361         final Collection<Uri> expectedUris = new HashSet<>();
362         expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
363         expectedUris.add(new Uri.Builder()
364                 .scheme(SCHEME_CONTENT)
365                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
366                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
367                 .appendPath(key)
368                 .build());
369 
370         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
371 
372         assertThat(descendants).containsExactlyElementsIn(expectedUris);
373     }
374 
375     @Test
getDescendantUris_platformSlice_returnsPlatformUriDescendant()376     public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
377         final String key = "platform_key";
378         insertSpecialCase(key, true /* isPlatformSlice */);
379         final Uri uri = new Uri.Builder()
380                 .scheme(SCHEME_CONTENT)
381                 .authority(SettingsSlicesContract.AUTHORITY)
382                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
383                 .build();
384         final Collection<Uri> expectedUris = new HashSet<>();
385         expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
386         expectedUris.add(new Uri.Builder()
387                 .scheme(SCHEME_CONTENT)
388                 .authority(SettingsSlicesContract.AUTHORITY)
389                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
390                 .appendPath(key)
391                 .build());
392 
393         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
394 
395         assertThat(descendants).containsExactlyElementsIn(expectedUris);
396     }
397 
398     @Test
getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant()399     public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() {
400         final String key = "platform_key";
401         insertSpecialCase(key, true /* isPlatformSlice */);
402         final Uri uri = new Uri.Builder()
403                 .scheme(SCHEME_CONTENT)
404                 .authority(SettingsSlicesContract.AUTHORITY)
405                 .build();
406         final Collection<Uri> expectedUris = new HashSet<>();
407         expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
408         expectedUris.add(new Uri.Builder()
409                 .scheme(SCHEME_CONTENT)
410                 .authority(SettingsSlicesContract.AUTHORITY)
411                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
412                 .appendPath(key)
413                 .build());
414 
415         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
416 
417         assertThat(descendants).containsExactlyElementsIn(expectedUris);
418     }
419 
420     @Test
getDescendantUris_noAuthorityNorPath_returnsAllUris()421     public void getDescendantUris_noAuthorityNorPath_returnsAllUris() {
422         final String platformKey = "platform_key";
423         final String oemKey = "oemKey";
424         insertSpecialCase(platformKey, true /* isPlatformSlice */);
425         insertSpecialCase(oemKey, false /* isPlatformSlice */);
426         final Uri uri = new Uri.Builder()
427                 .scheme(SCHEME_CONTENT)
428                 .build();
429         final Collection<Uri> expectedUris = new HashSet<>();
430         expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
431         expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
432         expectedUris.add(new Uri.Builder()
433                 .scheme(SCHEME_CONTENT)
434                 .authority(SettingsSlicesContract.AUTHORITY)
435                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
436                 .appendPath(platformKey)
437                 .build());
438         expectedUris.add(new Uri.Builder()
439                 .scheme(SCHEME_CONTENT)
440                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
441                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
442                 .appendPath(oemKey)
443                 .build());
444 
445         final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
446 
447         assertThat(descendants).containsExactlyElementsIn(expectedUris);
448     }
449 
450     @Test
onCreatePermissionRequest_returnsSettingIntent()451     public void onCreatePermissionRequest_returnsSettingIntent() {
452         final PendingIntent pendingIntent = mProvider.onCreatePermissionRequest(
453                 CustomSliceRegistry.FLASHLIGHT_SLICE_URI, "com.android.whaaaat");
454         final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS)
455                 .setPackage(Utils.SETTINGS_PACKAGE_NAME);
456         PendingIntent settingsPendingIntent =
457                 PendingIntent.getActivity(mContext, 0, settingsIntent, 0);
458 
459         assertThat(pendingIntent).isEqualTo(settingsPendingIntent);
460     }
461 
462     @Test
bindSlice_wifiSlice_returnsWifiSlice()463     public void bindSlice_wifiSlice_returnsWifiSlice() {
464         final Slice wifiSlice = mProvider.onBindSlice(CustomSliceRegistry.WIFI_SLICE_URI);
465 
466         assertThat(wifiSlice.getUri()).isEqualTo(CustomSliceRegistry.WIFI_SLICE_URI);
467     }
468 
469     @Test
bindSlice_flashlightSlice_returnsFlashlightSlice()470     public void bindSlice_flashlightSlice_returnsFlashlightSlice() {
471         Settings.Secure.putInt(
472                 mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
473 
474         final Slice flashlightSlice = mProvider.onBindSlice(
475                 CustomSliceRegistry.FLASHLIGHT_SLICE_URI);
476 
477         assertThat(flashlightSlice.getUri()).isEqualTo(CustomSliceRegistry.FLASHLIGHT_SLICE_URI);
478     }
479 
480     @Test
onSlicePinned_noIntentRegistered_specialCaseUri_doesNotCrash()481     public void onSlicePinned_noIntentRegistered_specialCaseUri_doesNotCrash() {
482         final Uri uri = new Uri.Builder()
483                 .scheme(ContentResolver.SCHEME_CONTENT)
484                 .authority(SettingsSlicesContract.AUTHORITY)
485                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
486                 .appendPath(SettingsSlicesContract.KEY_LOCATION)
487                 .build();
488 
489         mProvider.onSlicePinned(uri);
490     }
491 
492     @Implements(WifiScanWorker.class)
493     public static class ShadowWifiScanWorker {
494         private static WifiTracker mWifiTracker;
495 
496         @Implementation
onSlicePinned()497         protected void onSlicePinned() {
498             mWifiTracker = mock(WifiTracker.class);
499             mWifiTracker.onStart();
500         }
501 
502         @Implementation
onSliceUnpinned()503         protected void onSliceUnpinned() {
504             mWifiTracker.onStop();
505         }
506 
507         @Implementation
close()508         protected void close() {
509             mWifiTracker.onDestroy();
510         }
511 
getWifiTracker()512         static WifiTracker getWifiTracker() {
513             return mWifiTracker;
514         }
515     }
516 
517     @Test
onSlicePinned_backgroundWorker_started()518     public void onSlicePinned_backgroundWorker_started() {
519         mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
520 
521         verify(ShadowWifiScanWorker.getWifiTracker()).onStart();
522     }
523 
524     @Test
onSlicePinned_backgroundWorker_stopped()525     public void onSlicePinned_backgroundWorker_stopped() {
526         mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
527         mProvider.onSliceUnpinned(CustomSliceRegistry.WIFI_SLICE_URI);
528 
529         verify(ShadowWifiScanWorker.getWifiTracker()).onStop();
530     }
531 
532     @Test
shutdown_backgroundWorker_closed()533     public void shutdown_backgroundWorker_closed() {
534         mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
535         mProvider.shutdown();
536 
537         verify(ShadowWifiScanWorker.getWifiTracker()).onDestroy();
538     }
539 
540     @Test
541     @Config(qualifiers = "mcc998")
grantWhitelistedPackagePermissions_noWhitelist_shouldNotGrant()542     public void grantWhitelistedPackagePermissions_noWhitelist_shouldNotGrant() {
543         final List<Uri> uris = new ArrayList<>();
544         uris.add(Uri.parse("content://settings/slice"));
545 
546         SettingsSliceProvider.grantWhitelistedPackagePermissions(mContext, uris);
547 
548         verify(mManager, never()).grantSlicePermission(anyString(), any(Uri.class));
549     }
550 
551     @Test
552     @Config(qualifiers = "mcc999")
grantWhitelistedPackagePermissions_hasPackageWhitelist_shouldGrant()553     public void grantWhitelistedPackagePermissions_hasPackageWhitelist_shouldGrant() {
554         final List<Uri> uris = new ArrayList<>();
555         uris.add(Uri.parse("content://settings/slice"));
556 
557         SettingsSliceProvider.grantWhitelistedPackagePermissions(mContext, uris);
558 
559         verify(mManager)
560                 .grantSlicePermission("com.android.settings.slice_whitelist_package", uris.get(0));
561     }
562 
insertSpecialCase(String key)563     private void insertSpecialCase(String key) {
564         insertSpecialCase(key, true);
565     }
566 
insertSpecialCase(String key, boolean isPlatformSlice)567     private void insertSpecialCase(String key, boolean isPlatformSlice) {
568         final ContentValues values = new ContentValues();
569         values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
570         values.put(SlicesDatabaseHelper.IndexColumns.TITLE, TITLE);
571         values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, "s");
572         values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, "s");
573         values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, R.drawable.ic_settings_accent);
574         values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
575         values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, PREF_CONTROLLER);
576         values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
577         values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
578         final SQLiteDatabase db = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
579         db.beginTransaction();
580         try {
581             db.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
582             db.setTransactionSuccessful();
583         } finally {
584             db.endTransaction();
585         }
586         db.close();
587     }
588 
getDummyData()589     private static SliceData getDummyData() {
590         return new SliceData.Builder()
591                 .setKey(KEY)
592                 .setTitle(TITLE)
593                 .setSummary(SUMMARY)
594                 .setScreenTitle(SCREEN_TITLE)
595                 .setIcon(ICON)
596                 .setFragmentName(FRAGMENT_NAME)
597                 .setUri(URI)
598                 .setPreferenceControllerClassName(PREF_CONTROLLER)
599                 .build();
600     }
601 
602     @Implements(value = StrictMode.class)
603     public static class ShadowStrictMode {
604 
605         private static int sSetThreadPolicyCount;
606 
607         @Resetter
reset()608         public static void reset() {
609             sSetThreadPolicyCount = 0;
610         }
611 
612         @Implementation
setThreadPolicy(final StrictMode.ThreadPolicy policy)613         protected static void setThreadPolicy(final StrictMode.ThreadPolicy policy) {
614             sSetThreadPolicyCount++;
615         }
616 
isThreadPolicyOverridden()617         private static boolean isThreadPolicyOverridden() {
618             return sSetThreadPolicyCount != 0;
619         }
620     }
621 }
622