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.Mockito.spy;
25 
26 import android.app.ApplicationPackageManager;
27 import android.content.ComponentName;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.net.Uri;
31 import android.provider.SettingsSlicesContract;
32 import android.view.accessibility.AccessibilityManager;
33 
34 import com.android.settings.search.SearchFeatureProvider;
35 import com.android.settings.search.SearchFeatureProviderImpl;
36 import com.android.settings.testutils.DatabaseTestUtils;
37 import com.android.settings.testutils.FakeFeatureFactory;
38 import com.android.settings.testutils.FakeIndexProvider;
39 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
40 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
41 import com.android.settings.testutils.shadow.ShadowUserManager;
42 import com.android.settings.testutils.shadow.ShadowUtils;
43 import com.android.settingslib.search.SearchIndexableData;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.robolectric.RobolectricTestRunner;
50 import org.robolectric.RuntimeEnvironment;
51 import org.robolectric.annotation.Config;
52 import org.robolectric.annotation.Implementation;
53 import org.robolectric.annotation.Implements;
54 import org.robolectric.shadow.api.Shadow;
55 import org.robolectric.shadows.ShadowAccessibilityManager;
56 
57 import java.util.ArrayList;
58 import java.util.List;
59 import java.util.Locale;
60 
61 @RunWith(RobolectricTestRunner.class)
62 @Config(shadows = {ShadowUserManager.class, ShadowUtils.class,
63         SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
64         ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class})
65 public class SlicesDatabaseAccessorTest {
66 
67 
68     private Context mContext;
69     private SlicesDatabaseAccessor mAccessor;
70 
71     @Before
setUp()72     public void setUp() {
73         mContext = RuntimeEnvironment.application;
74         ShadowUserManager.getShadow().setIsAdminUser(true);
75         mAccessor = spy(new SlicesDatabaseAccessor(mContext));
76         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
77 
78         // Register the fake a11y Service
79         ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
80                 RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
81         shadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
82     }
83 
84     @After
cleanUp()85     public void cleanUp() {
86         DatabaseTestUtils.clearDb(mContext);
87     }
88 
89     @Test
testGetSliceDataFromKey_validKey_validSliceReturned()90     public void testGetSliceDataFromKey_validKey_validSliceReturned() {
91         String key = "key";
92         SliceTestUtils.insertSliceToDb(mContext, key);
93 
94         SliceData data = mAccessor.getSliceDataFromKey(key);
95 
96         assertThat(data.getKey()).isEqualTo(key);
97         assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE);
98         assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY);
99         assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE);
100         assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS);
101         assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON);
102         assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME);
103         assertThat(data.getUri()).isNull();
104         assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME);
105         assertThat(data.getHighlightMenuRes()).isEqualTo(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES);
106         assertThat(data.getUnavailableSliceSubtitle()).isNull();
107     }
108 
109     @Test
testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned()110     public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() {
111         String key = "key";
112         SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */,
113                 null /* customizedUnavailableSliceSubtitle */);
114 
115         SliceData data = mAccessor.getSliceDataFromKey(key);
116 
117         assertThat(data.getKey()).isEqualTo(key);
118         assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE);
119         assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY);
120         assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE);
121         assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS);
122         assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON);
123         assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME);
124         assertThat(data.getUri()).isNull();
125         assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME);
126         assertThat(data.getHighlightMenuRes()).isEqualTo(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES);
127     }
128 
129     @Test(expected = IllegalStateException.class)
testGetSliceDataFromKey_invalidKey_errorThrown()130     public void testGetSliceDataFromKey_invalidKey_errorThrown() {
131         String key = "key";
132 
133         mAccessor.getSliceDataFromKey(key);
134     }
135 
136     @Test
testGetSliceFromUri_validUri_validSliceReturned()137     public void testGetSliceFromUri_validUri_validSliceReturned() {
138         final String key = "key";
139         SliceTestUtils.insertSliceToDb(mContext, key);
140 
141         final Uri uri = new Uri.Builder()
142                 .scheme(ContentResolver.SCHEME_CONTENT)
143                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
144                 .appendPath("action")
145                 .appendPath(key)
146                 .build();
147 
148         SliceData data = mAccessor.getSliceDataFromUri(uri);
149 
150         assertThat(data.getKey()).isEqualTo(key);
151         assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE);
152         assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY);
153         assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE);
154         assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS);
155         assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON);
156         assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME);
157         assertThat(data.getUri()).isEqualTo(uri);
158         assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME);
159         assertThat(data.getHighlightMenuRes()).isEqualTo(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES);
160     }
161 
162     @Test(expected = IllegalStateException.class)
testGetSliceFromUri_invalidUri_errorThrown()163     public void testGetSliceFromUri_invalidUri_errorThrown() {
164         final Uri uri = new Uri.Builder()
165                 .scheme(ContentResolver.SCHEME_CONTENT)
166                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
167                 .appendPath("intent")
168                 .appendPath("durr")
169                 .build();
170         mAccessor.getSliceDataFromUri(uri);
171     }
172 
173     @Test
getDescendantUris_platformSlice_doesNotReturnOEMSlice()174     public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
175         final String key = "oem_key";
176         SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */,
177                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
178         final List<Uri> keys = mAccessor.getSliceUris(SettingsSlicesContract.AUTHORITY,
179                 true /* isPublicSlice */);
180 
181         assertThat(keys).isEmpty();
182     }
183 
184     @Test
getDescendantUris_oemSlice_doesNotReturnPlatformSlice()185     public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
186         final String key = "platform_key";
187         SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */,
188                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
189         final List<Uri> keys = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY,
190                 true /* isPublicSlice */);
191 
192         assertThat(keys).isEmpty();
193     }
194 
195     @Test
getDescendantUris_oemSlice_returnsOEMUriDescendant()196     public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
197         final String key = "oem_key";
198         SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */,
199                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
200         final List<Uri> keys = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY,
201                 true /* isPublicSlice */);
202 
203         assertThat(keys).containsExactly(
204                 Uri.parse("content://com.android.settings.slices/action/oem_key"));
205     }
206 
207     @Test
getDescendantUris_platformSlice_returnsPlatformUriDescendant()208     public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
209         final String key = "platform_key";
210         SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */,
211                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
212         final List<Uri> keys = mAccessor.getSliceUris(SettingsSlicesContract.AUTHORITY,
213                 true /* isPublicSlice */);
214 
215         assertThat(keys).containsExactly(
216                 Uri.parse("content://android.settings.slices/action/platform_key"));
217     }
218 
219     @Test
getSliceUris_publicSlice_returnPublicUri()220     public void getSliceUris_publicSlice_returnPublicUri() {
221         SliceTestUtils.insertSliceToDb(mContext, "test_public", false /* isPlatformSlice */,
222                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
223         SliceTestUtils.insertSliceToDb(mContext, "test_private", false /* isPlatformSlice */,
224                 null /* customizedUnavailableSliceSubtitle */, false /* isPublicSlice */);
225         final Uri expectedUri = new Uri.Builder()
226                 .scheme(SCHEME_CONTENT)
227                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
228                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
229                 .appendPath("test_public")
230                 .build();
231 
232         final List<Uri> uri = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY, true);
233 
234         assertThat(uri).containsExactly(expectedUri);
235     }
236 
237     @Test
getSliceUris_nonPublicSlice_returnNonPublicUri()238     public void getSliceUris_nonPublicSlice_returnNonPublicUri() {
239         SliceTestUtils.insertSliceToDb(mContext, "test_public", false /* isPlatformSlice */,
240                 null /* customizedUnavailableSliceSubtitle */, true /* isPublicSlice */);
241         SliceTestUtils.insertSliceToDb(mContext, "test_private", false /* isPlatformSlice */,
242                 null /* customizedUnavailableSliceSubtitle */, false /* isPublicSlice */);
243         final Uri expectedUri = new Uri.Builder()
244                 .scheme(SCHEME_CONTENT)
245                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
246                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
247                 .appendPath("test_private")
248                 .build();
249 
250         final List<Uri> uri = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY, false);
251 
252         assertThat(uri).containsExactly(expectedUri);
253     }
254 
255     @Test
256     @Config(qualifiers = "mcc999")
getSliceKeys_indexesDatabase()257     public void getSliceKeys_indexesDatabase() {
258         // Force new indexing
259         Locale.setDefault(new Locale("ca"));
260         final SearchFeatureProvider provider = new SearchFeatureProviderImpl();
261         final SlicesFeatureProvider sliceProvider = new SlicesFeatureProviderImpl();
262         final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest();
263         factory.searchFeatureProvider = provider;
264         factory.slicesFeatureProvider = sliceProvider;
265         // Fake the indexable list.
266         provider.getSearchIndexableResources().getProviderValues().clear();
267         provider.getSearchIndexableResources().getProviderValues().add(
268                 new SearchIndexableData(FakeIndexProvider.class,
269                         FakeIndexProvider.SEARCH_INDEX_DATA_PROVIDER));
270 
271         final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(mContext);
272         final List<Uri> keys = accessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY,
273                 true /* isPublicSlice */);
274 
275         assertThat(keys).isNotEmpty();
276     }
277 
278     @Test
testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned()279     public void testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned() {
280         String key = "key";
281         SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */,
282                 null /* customizedUnavailableSliceSubtitle */);
283 
284         SliceData data = mAccessor.getSliceDataFromKey(key);
285 
286         assertThat(data.getKey()).isEqualTo(key);
287         assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE);
288         assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY);
289         assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE);
290         assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS);
291         assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON);
292         assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME);
293         assertThat(data.getUri()).isNull();
294         assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME);
295         assertThat(data.getHighlightMenuRes()).isEqualTo(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES);
296         assertThat(data.getUnavailableSliceSubtitle()).isNull();
297     }
298 
299     @Test
testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned()300     public void testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned() {
301         String key = "key";
302         String subtitle = "subtitle";
303         SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, subtitle);
304 
305         SliceData data = mAccessor.getSliceDataFromKey(key);
306 
307         assertThat(data.getKey()).isEqualTo(key);
308         assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE);
309         assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY);
310         assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE);
311         assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS);
312         assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON);
313         assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME);
314         assertThat(data.getUri()).isNull();
315         assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME);
316         assertThat(data.getHighlightMenuRes()).isEqualTo(SliceTestUtils.FAKE_HIGHLIGHT_MENU_RES);
317         assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(subtitle);
318     }
319 
320     @Implements(ApplicationPackageManager.class)
321     public static class ShadowApplicationPackageManager extends
322             org.robolectric.shadows.ShadowApplicationPackageManager {
323 
324         @Implementation
getInstantAppResolverSettingsComponent()325         protected ComponentName getInstantAppResolverSettingsComponent() {
326             return null;
327         }
328     }
329 }
330