1 package com.android.settings.search;
2 
3 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SEARCHABLE;
4 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
5 
6 import static com.google.common.truth.Truth.assertThat;
7 
8 import static org.mockito.Mockito.mock;
9 import static org.mockito.Mockito.spy;
10 import static org.mockito.Mockito.when;
11 
12 import android.Manifest;
13 import android.content.Context;
14 import android.content.pm.ActivityInfo;
15 import android.content.pm.ProviderInfo;
16 import android.database.Cursor;
17 import android.net.Uri;
18 import android.os.Bundle;
19 import android.provider.SearchIndexablesContract;
20 
21 import com.android.settings.R;
22 import com.android.settings.accounts.ManagedProfileSettings;
23 import com.android.settings.dashboard.CategoryManager;
24 import com.android.settings.homepage.TopLevelSettings;
25 import com.android.settings.network.NetworkDashboardFragment;
26 import com.android.settings.testutils.FakeFeatureFactory;
27 import com.android.settingslib.drawer.ActivityTile;
28 import com.android.settingslib.drawer.CategoryKey;
29 import com.android.settingslib.drawer.DashboardCategory;
30 import com.android.settingslib.search.SearchIndexableData;
31 
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.robolectric.RobolectricTestRunner;
37 import org.robolectric.RuntimeEnvironment;
38 import org.robolectric.annotation.Config;
39 import org.robolectric.annotation.Implementation;
40 import org.robolectric.annotation.Implements;
41 import org.robolectric.annotation.Resetter;
42 
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.List;
46 
47 @RunWith(RobolectricTestRunner.class)
48 @Config(shadows = SettingsSearchIndexablesProviderTest.ShadowCategoryManager.class)
49 public class SettingsSearchIndexablesProviderTest {
50 
51     private static final String PACKAGE_NAME = "com.android.settings";
52     private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/";
53 
54     private Context mContext;
55     private SettingsSearchIndexablesProvider mProvider;
56     private FakeFeatureFactory mFakeFeatureFactory;
57 
58     @Before
setUp()59     public void setUp() {
60         mContext = RuntimeEnvironment.application;
61         mProvider = spy(new SettingsSearchIndexablesProvider());
62         ProviderInfo info = new ProviderInfo();
63         info.exported = true;
64         info.grantUriPermissions = true;
65         info.authority = PACKAGE_NAME;
66         info.readPermission = Manifest.permission.READ_SEARCH_INDEXABLES;
67         mProvider.attachInfo(RuntimeEnvironment.application, info);
68 
69         final SearchFeatureProvider featureProvider = new SearchFeatureProviderImpl();
70         featureProvider.getSearchIndexableResources().getProviderValues().clear();
71         featureProvider.getSearchIndexableResources().getProviderValues()
72                 .add(new SearchIndexableData(FakeSettingsFragment.class,
73                         FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER));
74         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
75         mFakeFeatureFactory.searchFeatureProvider = featureProvider;
76 
77         final ActivityInfo activityInfo = new ActivityInfo();
78         activityInfo.packageName = "pkg";
79         activityInfo.name = "class";
80         activityInfo.metaData = new Bundle();
81         activityInfo.metaData.putString(META_DATA_PREFERENCE_TITLE, "title");
82         final DashboardCategory category = new DashboardCategory("key");
83         when(mFakeFeatureFactory.dashboardFeatureProvider.getAllCategories())
84                 .thenReturn(Arrays.asList(category));
85         category.addTile(new ActivityTile(activityInfo, category.key));
86         ShadowCategoryManager.setDashboardCategory(category);
87     }
88 
89     @After
cleanUp()90     public void cleanUp() {
91         ShadowCategoryManager.reset();
92         mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class);
93     }
94 
95     @Test
testRawColumnFetched()96     public void testRawColumnFetched() {
97         Uri rawUri = Uri.parse(BASE_AUTHORITY + SearchIndexablesContract.INDEXABLES_RAW_PATH);
98 
99         final Cursor cursor = mProvider.query(rawUri,
100                 SearchIndexablesContract.INDEXABLES_RAW_COLUMNS, null, null, null);
101 
102         cursor.moveToFirst();
103         assertThat(cursor.getString(1)).isEqualTo(FakeSettingsFragment.TITLE);
104         assertThat(cursor.getString(2)).isEqualTo(FakeSettingsFragment.SUMMARY_ON);
105         assertThat(cursor.getString(3)).isEqualTo(FakeSettingsFragment.SUMMARY_OFF);
106         assertThat(cursor.getString(4)).isEqualTo(FakeSettingsFragment.ENTRIES);
107         assertThat(cursor.getString(5)).isEqualTo(FakeSettingsFragment.KEYWORDS);
108         assertThat(cursor.getString(6)).isEqualTo(FakeSettingsFragment.SCREEN_TITLE);
109         assertThat(cursor.getString(7)).isEqualTo(FakeSettingsFragment.CLASS_NAME);
110         assertThat(cursor.getInt(8)).isEqualTo(FakeSettingsFragment.ICON);
111         assertThat(cursor.getString(9)).isEqualTo(FakeSettingsFragment.INTENT_ACTION);
112         assertThat(cursor.getString(10)).isEqualTo(FakeSettingsFragment.TARGET_PACKAGE);
113         assertThat(cursor.getString(11)).isEqualTo(FakeSettingsFragment.TARGET_CLASS);
114         assertThat(cursor.getString(12)).isEqualTo(FakeSettingsFragment.KEY);
115     }
116 
117     @Test
testResourcesColumnFetched()118     public void testResourcesColumnFetched() {
119         Uri rawUri = Uri.parse(BASE_AUTHORITY + SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
120 
121         final Cursor cursor = mProvider.query(rawUri,
122                 SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS, null, null, null);
123 
124         cursor.moveToFirst();
125         assertThat(cursor.getCount()).isEqualTo(1);
126         assertThat(cursor.getInt(1)).isEqualTo(R.xml.display_settings);
127         assertThat(cursor.getString(2)).isEqualTo(FakeSettingsFragment.CLASS_NAME);
128         assertThat(cursor.getInt(3)).isEqualTo(0);
129         assertThat(cursor.getString(4)).isNull();
130         assertThat(cursor.getString(5)).isNull();
131         assertThat(cursor.getString(6)).isNull();
132     }
133 
134     @Test
135     @Config(qualifiers = "mcc999")
testNonIndexablesColumnFetched()136     public void testNonIndexablesColumnFetched() {
137         final Uri rawUri = Uri.parse(
138                 BASE_AUTHORITY + SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
139 
140         final List<String> keys = new ArrayList<>();
141 
142         try (Cursor cursor = mProvider.query(rawUri,
143                 SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null)) {
144             while (cursor.moveToNext()) {
145                 keys.add(cursor.getString(0));
146             }
147         }
148 
149         assertThat(keys).hasSize(3);
150         assertThat(keys).containsAtLeast("pref_key_1", "pref_key_3", "pref_key_5");
151     }
152 
153     @Test
refreshSearchEnabledState_classNotFoundInCategoryMap_hasInjectionRawData()154     public void refreshSearchEnabledState_classNotFoundInCategoryMap_hasInjectionRawData() {
155         mProvider.refreshSearchEnabledState(mContext,
156                 ManagedProfileSettings.SEARCH_INDEX_DATA_PROVIDER);
157 
158         assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
159     }
160 
161     @Test
refreshSearchEnabledState_noDashboardCategory_hasInjectionRawData()162     public void refreshSearchEnabledState_noDashboardCategory_hasInjectionRawData() {
163         ShadowCategoryManager.setDashboardCategory(null);
164 
165         mProvider.refreshSearchEnabledState(mContext,
166                 TopLevelSettings.SEARCH_INDEX_DATA_PROVIDER);
167 
168         assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
169     }
170 
171     @Test
refreshSearchEnabledState_pageSearchEnabled_hasInjectionRawData()172     public void refreshSearchEnabledState_pageSearchEnabled_hasInjectionRawData() {
173         mProvider.refreshSearchEnabledState(mContext,
174                 NetworkDashboardFragment.SEARCH_INDEX_DATA_PROVIDER);
175 
176         assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
177     }
178 
179     @Test
refreshSearchEnabledState_pageSearchDisable_noInjectionRawData()180     public void refreshSearchEnabledState_pageSearchDisable_noInjectionRawData() {
181         mProvider.refreshSearchEnabledState(mContext,
182                 TopLevelSettings.SEARCH_INDEX_DATA_PROVIDER);
183 
184         assertThat(mProvider.getInjectionIndexableRawData(mContext)).isEmpty();
185     }
186 
187     @Test
isEligibleForIndexing_isSettingsInjectedItem_shouldReturnFalse()188     public void isEligibleForIndexing_isSettingsInjectedItem_shouldReturnFalse() {
189         final ActivityInfo activityInfo = new ActivityInfo();
190         activityInfo.packageName = PACKAGE_NAME;
191         activityInfo.name = "class";
192         final ActivityTile activityTile = new ActivityTile(activityInfo,
193                 CategoryKey.CATEGORY_SYSTEM);
194 
195         assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse();
196     }
197 
198     @Test
isEligibleForIndexing_normalInjectedItem_shouldReturnTrue()199     public void isEligibleForIndexing_normalInjectedItem_shouldReturnTrue() {
200         final ActivityInfo activityInfo = new ActivityInfo();
201         activityInfo.packageName = "pkg";
202         activityInfo.name = "class";
203         final ActivityTile activityTile = new ActivityTile(activityInfo,
204                 CategoryKey.CATEGORY_CONNECT);
205 
206         assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isTrue();
207     }
208 
209     @Test
isEligibleForIndexing_disabledByMetadata_shouldReturnFalse()210     public void isEligibleForIndexing_disabledByMetadata_shouldReturnFalse() {
211         final ActivityInfo activityInfo = new ActivityInfo();
212         activityInfo.packageName = PACKAGE_NAME;
213         activityInfo.name = "class";
214         activityInfo.metaData = new Bundle();
215         activityInfo.metaData.putBoolean(META_DATA_PREFERENCE_SEARCHABLE, false);
216         final ActivityTile activityTile = new ActivityTile(activityInfo,
217                 CategoryKey.CATEGORY_CONNECT);
218 
219         assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse();
220     }
221 
222     @Implements(CategoryManager.class)
223     public static class ShadowCategoryManager {
224 
225         private static DashboardCategory sCategory;
226 
227         @Resetter
reset()228         static void reset() {
229             sCategory = null;
230         }
231 
232         @Implementation
getTilesByCategory(Context context, String categoryKey)233         public DashboardCategory getTilesByCategory(Context context, String categoryKey) {
234             return sCategory;
235         }
236 
setDashboardCategory(DashboardCategory category)237         static void setDashboardCategory(DashboardCategory category) {
238             sCategory = category;
239         }
240     }
241 }
242