Home | History | Annotate | Download | only in applications
      1 /*
      2  * Copyright (C) 2017 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.applications;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 
     21 import static org.mockito.ArgumentMatchers.anyString;
     22 import static org.mockito.Mockito.verify;
     23 import static org.mockito.Mockito.when;
     24 import static org.robolectric.shadow.api.Shadow.extract;
     25 
     26 import android.annotation.UserIdInt;
     27 import android.app.ApplicationPackageManager;
     28 import android.app.usage.IStorageStatsManager;
     29 import android.app.usage.StorageStats;
     30 import android.app.usage.StorageStatsManager;
     31 import android.content.ComponentName;
     32 import android.content.Context;
     33 import android.content.Intent;
     34 import android.content.IntentFilter;
     35 import android.content.pm.ActivityInfo;
     36 import android.content.pm.ApplicationInfo;
     37 import android.content.pm.PackageManager;
     38 import android.content.pm.ResolveInfo;
     39 import android.graphics.drawable.ColorDrawable;
     40 import android.graphics.drawable.Drawable;
     41 import android.os.Handler;
     42 import android.os.UserHandle;
     43 import android.util.IconDrawableFactory;
     44 
     45 import com.android.settingslib.applications.ApplicationsState.AppEntry;
     46 import com.android.settingslib.applications.ApplicationsState.Callbacks;
     47 import com.android.settingslib.applications.ApplicationsState.Session;
     48 import com.android.settingslib.SettingsLibRobolectricTestRunner;
     49 import com.android.settingslib.testutils.shadow.ShadowUserManager;
     50 
     51 import org.junit.Before;
     52 import org.junit.Test;
     53 import org.junit.runner.RunWith;
     54 import org.mockito.ArgumentCaptor;
     55 import org.mockito.ArgumentMatchers;
     56 import org.mockito.Captor;
     57 import org.mockito.Mock;
     58 import org.mockito.MockitoAnnotations;
     59 import org.robolectric.RuntimeEnvironment;
     60 import org.robolectric.annotation.Config;
     61 import org.robolectric.annotation.Implementation;
     62 import org.robolectric.annotation.Implements;
     63 import org.robolectric.shadow.api.Shadow;
     64 import org.robolectric.shadows.ShadowContextImpl;
     65 import org.robolectric.shadows.ShadowLooper;
     66 
     67 import java.util.ArrayList;
     68 import java.util.List;
     69 import java.util.UUID;
     70 
     71 @RunWith(SettingsLibRobolectricTestRunner.class)
     72 @Config(shadows = {ShadowUserManager.class,
     73         ApplicationsStateRoboTest.ShadowIconDrawableFactory.class,
     74         ApplicationsStateRoboTest.ShadowPackageManager.class})
     75 public class ApplicationsStateRoboTest {
     76 
     77     private final static String HOME_PACKAGE_NAME = "com.android.home";
     78     private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable";
     79 
     80     /** Class under test */
     81     private ApplicationsState mApplicationsState;
     82 
     83     @Mock
     84     private Callbacks mCallbacks;
     85     @Captor
     86     private ArgumentCaptor<ArrayList<AppEntry>> mAppEntriesCaptor;
     87     @Mock
     88     private StorageStatsManager mStorageStatsManager;
     89 
     90     @Implements(value = IconDrawableFactory.class, inheritImplementationMethods = true)
     91     public static class ShadowIconDrawableFactory {
     92 
     93         @Implementation
     94         public Drawable getBadgedIcon(ApplicationInfo appInfo) {
     95             return new ColorDrawable(0);
     96         }
     97     }
     98 
     99     @Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
    100     public static class ShadowPackageManager extends
    101             org.robolectric.shadows.ShadowApplicationPackageManager {
    102 
    103         @Implementation
    104         public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
    105             ResolveInfo resolveInfo = new ResolveInfo();
    106             resolveInfo.activityInfo = new ActivityInfo();
    107             resolveInfo.activityInfo.packageName = HOME_PACKAGE_NAME;
    108             resolveInfo.activityInfo.enabled = true;
    109             outActivities.add(resolveInfo);
    110             return ComponentName.createRelative(resolveInfo.activityInfo.packageName, "foo");
    111         }
    112 
    113         public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
    114                 @PackageManager.ResolveInfoFlags int flags, @UserIdInt int userId) {
    115             List<ResolveInfo> resolveInfos = new ArrayList<>();
    116             ResolveInfo resolveInfo = new ResolveInfo();
    117             resolveInfo.activityInfo = new ActivityInfo();
    118             resolveInfo.activityInfo.packageName = LAUNCHABLE_PACKAGE_NAME;
    119             resolveInfo.activityInfo.enabled = true;
    120             resolveInfo.filter = new IntentFilter();
    121             resolveInfo.filter.addCategory(Intent.CATEGORY_LAUNCHER);
    122             resolveInfos.add(resolveInfo);
    123             return resolveInfos;
    124         }
    125     }
    126 
    127     @Before
    128     public void setUp() throws Exception {
    129         MockitoAnnotations.initMocks(this);
    130 
    131         // Robolectric does not know about the StorageStatsManager as a system service.
    132         // Registering a mock of this service as a replacement.
    133         ShadowContextImpl shadowContext = Shadow.extract(
    134                 RuntimeEnvironment.application.getBaseContext());
    135         shadowContext.setSystemService(Context.STORAGE_STATS_SERVICE, mStorageStatsManager);
    136         StorageStats storageStats = new StorageStats();
    137         storageStats.codeBytes = 10;
    138         storageStats.dataBytes = 20;
    139         storageStats.cacheBytes = 30;
    140         when(mStorageStatsManager.queryStatsForPackage(ArgumentMatchers.any(UUID.class),
    141                 anyString(), ArgumentMatchers.any(UserHandle.class))).thenReturn(storageStats);
    142 
    143         mApplicationsState = ApplicationsState.getInstance(RuntimeEnvironment.application);
    144         mApplicationsState.clearEntries();
    145     }
    146 
    147     private ApplicationInfo createApplicationInfo(String packageName) {
    148         ApplicationInfo appInfo = new ApplicationInfo();
    149         appInfo.sourceDir = "foo";
    150         appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
    151         appInfo.storageUuid = UUID.randomUUID();
    152         appInfo.packageName = packageName;
    153         return appInfo;
    154     }
    155 
    156     private AppEntry createAppEntry(ApplicationInfo appInfo, int id) {
    157         AppEntry appEntry = new AppEntry(RuntimeEnvironment.application, appInfo, id);
    158         appEntry.label = "label";
    159         appEntry.mounted = true;
    160         return appEntry;
    161     }
    162 
    163     private void addApp(String packageName, int id) {
    164         ApplicationInfo appInfo = createApplicationInfo(packageName);
    165         AppEntry appEntry = createAppEntry(appInfo, id);
    166         mApplicationsState.mAppEntries.add(appEntry);
    167         mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry);
    168     }
    169 
    170     private void processAllMessages() {
    171         Handler mainHandler = mApplicationsState.mMainHandler;
    172         Handler bkgHandler = mApplicationsState.mBackgroundHandler;
    173         ShadowLooper shadowBkgLooper = extract(bkgHandler.getLooper());
    174         ShadowLooper shadowMainLooper = extract(mainHandler.getLooper());
    175         shadowBkgLooper.idle();
    176         shadowMainLooper.idle();
    177     }
    178 
    179     private AppEntry findAppEntry(List<AppEntry> appEntries, long id) {
    180         for (AppEntry appEntry : appEntries) {
    181             if (appEntry.id == id) {
    182                 return appEntry;
    183             }
    184         }
    185         return null;
    186     }
    187 
    188     @Test
    189     public void testDefaultSessionLoadsAll() {
    190         Session session = mApplicationsState.newSession(mCallbacks);
    191         session.onResume();
    192 
    193         addApp(HOME_PACKAGE_NAME,1);
    194         addApp(LAUNCHABLE_PACKAGE_NAME,2);
    195         session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
    196         processAllMessages();
    197         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
    198 
    199         List<AppEntry> appEntries = mAppEntriesCaptor.getValue();
    200         assertThat(appEntries.size()).isEqualTo(2);
    201 
    202         for (AppEntry appEntry : appEntries) {
    203             assertThat(appEntry.size).isGreaterThan(0L);
    204             assertThat(appEntry.icon).isNotNull();
    205         }
    206 
    207         AppEntry homeEntry = findAppEntry(appEntries, 1);
    208         assertThat(homeEntry.isHomeApp).isTrue();
    209         assertThat(homeEntry.hasLauncherEntry).isFalse();
    210 
    211         AppEntry launchableEntry = findAppEntry(appEntries, 2);
    212         assertThat(launchableEntry.hasLauncherEntry).isTrue();
    213         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
    214         session.onDestroy();
    215     }
    216 
    217     @Test
    218     public void testCustomSessionLoadsIconsOnly() {
    219         Session session = mApplicationsState.newSession(mCallbacks);
    220         session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
    221         session.onResume();
    222 
    223         addApp(LAUNCHABLE_PACKAGE_NAME,1);
    224         session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
    225         processAllMessages();
    226         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
    227 
    228         List<AppEntry> appEntries = mAppEntriesCaptor.getValue();
    229         assertThat(appEntries.size()).isEqualTo(1);
    230 
    231         AppEntry launchableEntry = findAppEntry(appEntries, 1);
    232         assertThat(launchableEntry.icon).isNotNull();
    233         assertThat(launchableEntry.size).isEqualTo(-1);
    234         assertThat(launchableEntry.hasLauncherEntry).isFalse();
    235         session.onDestroy();
    236     }
    237 
    238     @Test
    239     public void testCustomSessionLoadsSizesOnly() {
    240         Session session = mApplicationsState.newSession(mCallbacks);
    241         session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
    242         session.onResume();
    243 
    244         addApp(LAUNCHABLE_PACKAGE_NAME,1);
    245         session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
    246         processAllMessages();
    247         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
    248 
    249         List<AppEntry> appEntries = mAppEntriesCaptor.getValue();
    250         assertThat(appEntries.size()).isEqualTo(1);
    251 
    252         AppEntry launchableEntry = findAppEntry(appEntries, 1);
    253         assertThat(launchableEntry.icon).isNull();
    254         assertThat(launchableEntry.hasLauncherEntry).isFalse();
    255         assertThat(launchableEntry.size).isGreaterThan(0L);
    256         session.onDestroy();
    257     }
    258 
    259     @Test
    260     public void testCustomSessionLoadsHomeOnly() {
    261         Session session = mApplicationsState.newSession(mCallbacks);
    262         session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
    263         session.onResume();
    264 
    265         addApp(HOME_PACKAGE_NAME,1);
    266         session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
    267         processAllMessages();
    268         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
    269 
    270         List<AppEntry> appEntries = mAppEntriesCaptor.getValue();
    271         assertThat(appEntries.size()).isEqualTo(1);
    272 
    273         AppEntry launchableEntry = findAppEntry(appEntries, 1);
    274         assertThat(launchableEntry.icon).isNull();
    275         assertThat(launchableEntry.hasLauncherEntry).isFalse();
    276         assertThat(launchableEntry.size).isEqualTo(-1);
    277         assertThat(launchableEntry.isHomeApp).isTrue();
    278         session.onDestroy();
    279     }
    280 
    281     @Test
    282     public void testCustomSessionLoadsLeanbackOnly() {
    283         Session session = mApplicationsState.newSession(mCallbacks);
    284         session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
    285         session.onResume();
    286 
    287         addApp(LAUNCHABLE_PACKAGE_NAME,1);
    288         session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
    289         processAllMessages();
    290         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
    291 
    292         List<AppEntry> appEntries = mAppEntriesCaptor.getValue();
    293         assertThat(appEntries.size()).isEqualTo(1);
    294 
    295         AppEntry launchableEntry = findAppEntry(appEntries, 1);
    296         assertThat(launchableEntry.icon).isNull();
    297         assertThat(launchableEntry.size).isEqualTo(-1);
    298         assertThat(launchableEntry.isHomeApp).isFalse();
    299         assertThat(launchableEntry.hasLauncherEntry).isTrue();
    300         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
    301         session.onDestroy();
    302     }
    303 }
    304