Home | History | Annotate | Download | only in drawer
      1 /*
      2  * Copyright (C) 2016 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 package com.android.settingslib.drawer;
     18 
     19 import android.app.ActivityManager;
     20 import static org.mockito.Mockito.verify;
     21 import android.content.IContentProvider;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.pm.ActivityInfo;
     26 import android.content.pm.ApplicationInfo;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.PackageManager.NameNotFoundException;
     29 import android.content.pm.ResolveInfo;
     30 import android.content.res.Resources;
     31 import android.net.Uri;
     32 import android.os.Bundle;
     33 import android.os.RemoteException;
     34 import android.os.UserHandle;
     35 import android.os.UserManager;
     36 import android.provider.Settings.Global;
     37 import android.text.TextUtils;
     38 import android.util.ArrayMap;
     39 import android.util.Pair;
     40 
     41 import com.android.settingslib.SuggestionParser;
     42 import com.android.settingslib.TestConfig;
     43 import com.android.settingslib.drawer.TileUtilsTest;
     44 import static org.mockito.Mockito.atLeastOnce;
     45 
     46 import org.junit.Before;
     47 import org.junit.Test;
     48 import org.junit.runner.RunWith;
     49 import org.mockito.ArgumentMatcher;
     50 import org.mockito.Mock;
     51 import org.mockito.MockitoAnnotations;
     52 import org.robolectric.shadows.ShadowApplication;
     53 import org.robolectric.RobolectricTestRunner;
     54 import org.robolectric.RuntimeEnvironment;
     55 import org.robolectric.annotation.Config;
     56 
     57 import java.util.ArrayList;
     58 import java.util.List;
     59 import java.util.Map;
     60 
     61 import static com.google.common.truth.Truth.assertThat;
     62 import static org.mockito.Matchers.any;
     63 import static org.mockito.Matchers.anyInt;
     64 import static org.mockito.Matchers.anyString;
     65 import static org.mockito.Matchers.argThat;
     66 import static org.mockito.Matchers.eq;
     67 import static org.mockito.Mockito.spy;
     68 import static org.mockito.Mockito.when;
     69 import org.mockito.ArgumentCaptor;
     70 
     71 
     72 @RunWith(RobolectricTestRunner.class)
     73 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
     74 public class TileUtilsTest {
     75 
     76     @Mock
     77     private Context mContext;
     78     @Mock
     79     private PackageManager mPackageManager;
     80     @Mock
     81     private Resources mResources;
     82     @Mock
     83     private UserManager mUserManager;
     84     @Mock
     85     private IContentProvider mIContentProvider;
     86     @Mock
     87     private ContentResolver mContentResolver;
     88 
     89     private static final String URI_GET_SUMMARY = "content://authority/text/summary";
     90     private static final String URI_GET_ICON = "content://authority/icon/my_icon";
     91 
     92     @Before
     93     public void setUp() throws NameNotFoundException {
     94         MockitoAnnotations.initMocks(this);
     95         when(mContext.getPackageManager()).thenReturn(mPackageManager);
     96         when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
     97         mContentResolver = spy(RuntimeEnvironment.application.getContentResolver());
     98         when(mContext.getContentResolver()).thenReturn(mContentResolver);
     99     }
    100 
    101     @Test
    102     public void getTilesForIntent_shouldParseCategory() {
    103         final String testCategory = "category1";
    104         Intent intent = new Intent();
    105         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    106         List<Tile> outTiles = new ArrayList<>();
    107         List<ResolveInfo> info = new ArrayList<>();
    108         info.add(newInfo(true, testCategory));
    109         Map<Pair<String, String>, Tile> cache = new ArrayMap<>();
    110         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    111                 .thenReturn(info);
    112 
    113         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    114                 null /* defaultCategory */, outTiles, false /* usePriority */,
    115                 false /* checkCategory */);
    116 
    117         assertThat(outTiles.size()).isEqualTo(1);
    118         assertThat(outTiles.get(0).category).isEqualTo(testCategory);
    119     }
    120 
    121     @Test
    122     public void getTilesForIntent_shouldParseKeyHintForSystemApp() {
    123         String keyHint = "key";
    124         Intent intent = new Intent();
    125         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    126         List<Tile> outTiles = new ArrayList<>();
    127         List<ResolveInfo> info = new ArrayList<>();
    128         ResolveInfo resolveInfo = newInfo(true, null /* category */, keyHint);
    129         info.add(resolveInfo);
    130 
    131         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    132                 .thenReturn(info);
    133 
    134         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    135                 null /* defaultCategory */, outTiles, false /* usePriority */,
    136                 false /* checkCategory */);
    137 
    138         assertThat(outTiles.size()).isEqualTo(1);
    139         assertThat(outTiles.get(0).key).isEqualTo(keyHint);
    140     }
    141 
    142     @Test
    143     public void getTilesForIntent_shouldSkipNonSystemApp() {
    144         final String testCategory = "category1";
    145         Intent intent = new Intent();
    146         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    147         List<Tile> outTiles = new ArrayList<>();
    148         List<ResolveInfo> info = new ArrayList<>();
    149         info.add(newInfo(false, testCategory));
    150 
    151         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    152                 .thenReturn(info);
    153 
    154         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    155                 null /* defaultCategory */, outTiles, false /* usePriority */,
    156                 false /* checkCategory */);
    157 
    158         assertThat(outTiles.isEmpty()).isTrue();
    159     }
    160 
    161     @Test
    162     public void getTilesForIntent_shouldSkipFilteredApps() {
    163         final String testCategory = "category1";
    164         Intent intent = new Intent();
    165         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    166         List<Tile> outTiles = new ArrayList<>();
    167         List<ResolveInfo> info = new ArrayList<>();
    168         ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
    169                 URI_GET_SUMMARY);
    170         addMetadataToInfo(resolveInfo, "com.android.settings.require_account", "com.google");
    171         addMetadataToInfo(resolveInfo, "com.android.settings.require_connection", "true");
    172         info.add(resolveInfo);
    173 
    174         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    175                 .thenReturn(info);
    176 
    177         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    178                 null /* defaultCategory */, outTiles, false /* usePriority */,
    179                 false /* checkCategory */);
    180 
    181         assertThat(outTiles.size()).isEqualTo(1);
    182         SuggestionParser parser = new SuggestionParser(mContext, null);
    183         parser.filterSuggestions(outTiles, 0, false);
    184         assertThat(outTiles.size()).isEqualTo(0);
    185     }
    186 
    187     @Test
    188     public void getCategories_shouldHandleExtraIntentAction() {
    189         final String testCategory = "category1";
    190         final String testAction = "action1";
    191         Map<Pair<String, String>, Tile> cache = new ArrayMap<>();
    192         List<ResolveInfo> info = new ArrayList<>();
    193         info.add(newInfo(true, testCategory));
    194         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
    195         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
    196         List<UserHandle> userHandleList = new ArrayList<>();
    197         userHandleList.add(UserHandle.CURRENT);
    198         when(mUserManager.getUserProfiles()).thenReturn(userHandleList);
    199 
    200         when(mPackageManager.queryIntentActivitiesAsUser(argThat(new ArgumentMatcher<Intent>() {
    201             public boolean matches(Object event) {
    202                 return testAction.equals(((Intent) event).getAction());
    203             }
    204         }), anyInt(), anyInt())).thenReturn(info);
    205 
    206         List<DashboardCategory> categoryList = TileUtils.getCategories(
    207             mContext, cache, false /* categoryDefinedInManifest */, testAction,
    208             TileUtils.SETTING_PKG);
    209         assertThat(categoryList.get(0).tiles.get(0).category).isEqualTo(testCategory);
    210     }
    211 
    212     @Test
    213     public void getCategories_withPackageName() throws Exception {
    214         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
    215         Map<Pair<String, String>, Tile> cache = new ArrayMap<>();
    216         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
    217         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
    218         List<UserHandle> userHandleList = new ArrayList<>();
    219 
    220         userHandleList.add(new UserHandle(ActivityManager.getCurrentUser()));
    221         when(mUserManager.getUserProfiles()).thenReturn(userHandleList);
    222 
    223         TileUtils.getCategories(
    224             mContext, cache, false /* categoryDefinedInManifest */, null /* action */,
    225             TileUtils.SETTING_PKG);
    226         verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser(
    227             intentCaptor.capture(), anyInt(), anyInt());
    228 
    229         assertThat(intentCaptor.getAllValues().get(0).getPackage())
    230             .isEqualTo(TileUtils.SETTING_PKG);
    231     }
    232 
    233     @Test
    234     public void getTilesForIntent_shouldReadMetadataTitleAsString() throws RemoteException {
    235         Intent intent = new Intent();
    236         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    237         List<Tile> outTiles = new ArrayList<>();
    238         List<ResolveInfo> info = new ArrayList<>();
    239         ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
    240                 URI_GET_SUMMARY, "my title", 0);
    241         info.add(resolveInfo);
    242 
    243         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    244                 .thenReturn(info);
    245 
    246         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    247                 null /* defaultCategory */, outTiles, false /* usePriority */,
    248                 false /* checkCategory */);
    249 
    250         assertThat(outTiles.size()).isEqualTo(1);
    251         assertThat(outTiles.get(0).title).isEqualTo("my title");
    252     }
    253 
    254     @Test
    255     public void getTilesForIntent_shouldReadMetadataTitleFromResource() throws RemoteException {
    256         Intent intent = new Intent();
    257         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    258         List<Tile> outTiles = new ArrayList<>();
    259         List<ResolveInfo> info = new ArrayList<>();
    260         ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
    261                 URI_GET_SUMMARY, null, 123);
    262         info.add(resolveInfo);
    263 
    264         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    265                 .thenReturn(info);
    266 
    267         when(mResources.getString(eq(123)))
    268                 .thenReturn("my localized title");
    269 
    270         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    271                 null /* defaultCategory */, outTiles, false /* usePriority */,
    272                 false /* checkCategory */);
    273 
    274         assertThat(outTiles.size()).isEqualTo(1);
    275         assertThat(outTiles.get(0).title).isEqualTo("my localized title");
    276     }
    277 
    278     @Test
    279     public void getTilesForIntent_shouldNotProcessInvalidUriContentSystemApp()
    280             throws RemoteException {
    281         Intent intent = new Intent();
    282         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    283         List<Tile> outTiles = new ArrayList<>();
    284         List<ResolveInfo> info = new ArrayList<>();
    285         ResolveInfo resolveInfo = newInfo(true, null /* category */, null, null, URI_GET_SUMMARY);
    286         info.add(resolveInfo);
    287 
    288         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    289                 .thenReturn(info);
    290 
    291         // Case 1: No provider associated with the uri specified.
    292         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    293                 null /* defaultCategory */, outTiles, false /* usePriority */,
    294                 false /* checkCategory */);
    295 
    296         assertThat(outTiles.size()).isEqualTo(1);
    297         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
    298         assertThat(outTiles.get(0).summary).isEqualTo("static-summary");
    299 
    300         // Case 2: Empty bundle.
    301         Bundle bundle = new Bundle();
    302         when(mIContentProvider.call(anyString(),
    303                 eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
    304                 any())).thenReturn(bundle);
    305         when(mContentResolver.acquireUnstableProvider(anyString()))
    306                 .thenReturn(mIContentProvider);
    307         when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
    308                 .thenReturn(mIContentProvider);
    309 
    310         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    311                 null /* defaultCategory */, outTiles, false /* usePriority */,
    312                 false /* checkCategory */);
    313 
    314         assertThat(outTiles.size()).isEqualTo(1);
    315         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
    316         assertThat(outTiles.get(0).summary).isEqualTo("static-summary");
    317     }
    318 
    319     @Test
    320     public void getTilesForIntent_shouldProcessUriContentForSystemApp() throws RemoteException {
    321         Intent intent = new Intent();
    322         Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
    323         List<Tile> outTiles = new ArrayList<>();
    324         List<ResolveInfo> info = new ArrayList<>();
    325         ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
    326                 URI_GET_SUMMARY);
    327         info.add(resolveInfo);
    328 
    329         when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
    330                 .thenReturn(info);
    331 
    332         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
    333                 null /* defaultCategory */, outTiles, false /* usePriority */,
    334                 false /* checkCategory */);
    335 
    336         assertThat(outTiles.size()).isEqualTo(1);
    337     }
    338 
    339     public static ResolveInfo newInfo(boolean systemApp, String category) {
    340         return newInfo(systemApp, category, null);
    341     }
    342 
    343     private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
    344         return newInfo(systemApp, category, keyHint, null, null);
    345     }
    346 
    347     private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
    348             String iconUri, String summaryUri) {
    349         return newInfo(systemApp, category, keyHint, iconUri, summaryUri, null, 0);
    350     }
    351 
    352     private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
    353             String iconUri, String summaryUri, String title, int titleResId) {
    354 
    355         ResolveInfo info = new ResolveInfo();
    356         info.system = systemApp;
    357         info.activityInfo = new ActivityInfo();
    358         info.activityInfo.packageName = "abc";
    359         info.activityInfo.name = "123";
    360         info.activityInfo.metaData = new Bundle();
    361         info.activityInfo.metaData.putString("com.android.settings.category", category);
    362         info.activityInfo.metaData.putInt("com.android.settings.icon", 314159);
    363         info.activityInfo.metaData.putString("com.android.settings.summary", "static-summary");
    364         if (keyHint != null) {
    365             info.activityInfo.metaData.putString("com.android.settings.keyhint", keyHint);
    366         }
    367         if (iconUri != null) {
    368             info.activityInfo.metaData.putString("com.android.settings.icon_uri", iconUri);
    369         }
    370         if (summaryUri != null) {
    371             info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri);
    372         }
    373         if (title != null) {
    374             info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
    375         }
    376         if (titleResId != 0) {
    377             info.activityInfo.metaData.putInt(
    378                     TileUtils.META_DATA_PREFERENCE_TITLE_RES_ID, titleResId);
    379         }
    380         info.activityInfo.applicationInfo = new ApplicationInfo();
    381         if (systemApp) {
    382             info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
    383         }
    384         return info;
    385     }
    386 
    387     private void addMetadataToInfo(ResolveInfo info, String key, String value) {
    388         if (!TextUtils.isEmpty(key)) {
    389             if (info.activityInfo == null) {
    390                 info.activityInfo = new ActivityInfo();
    391             }
    392             if (info.activityInfo.metaData == null) {
    393                 info.activityInfo.metaData = new Bundle();
    394             }
    395             info.activityInfo.metaData.putString(key, value);
    396         }
    397     }
    398 }
    399