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.settings.applications;
     18 
     19 import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
     20 import static com.google.common.truth.Truth.assertThat;
     21 import static org.mockito.Matchers.anyInt;
     22 import static org.mockito.Matchers.anyObject;
     23 import static org.mockito.Matchers.argThat;
     24 import static org.mockito.Matchers.eq;
     25 import static org.mockito.Mockito.atLeast;
     26 import static org.mockito.Mockito.verify;
     27 import static org.mockito.Mockito.when;
     28 
     29 import android.content.Intent;
     30 import android.content.pm.ApplicationInfo;
     31 import android.content.pm.PackageManager;
     32 import android.content.pm.ResolveInfo;
     33 import android.content.pm.UserInfo;
     34 import android.os.UserHandle;
     35 import android.os.UserManager;
     36 
     37 import com.android.settings.testutils.SettingsRobolectricTestRunner;
     38 import com.android.settingslib.wrapper.PackageManagerWrapper;
     39 
     40 import org.junit.Before;
     41 import org.junit.Test;
     42 import org.junit.runner.RunWith;
     43 import org.mockito.ArgumentMatcher;
     44 import org.mockito.Mock;
     45 import org.mockito.MockitoAnnotations;
     46 import org.robolectric.shadows.ShadowApplication;
     47 
     48 import java.util.Arrays;
     49 import java.util.Collections;
     50 import java.util.HashSet;
     51 import java.util.List;
     52 import java.util.Set;
     53 
     54 @RunWith(SettingsRobolectricTestRunner.class)
     55 public final class InstalledAppListerTest {
     56 
     57     private final String APP_1 = "app1";
     58     private final String APP_2 = "app2";
     59     private final String APP_3 = "app3";
     60     private final String APP_4 = "app4";
     61     private final String APP_5 = "app5";
     62     private final String APP_6 = "app6";
     63 
     64     private final int MAIN_USER_ID = 0;
     65     private final int MANAGED_PROFILE_ID = 10;
     66 
     67     private final int PER_USER_UID_RANGE = 100000;
     68     private final int MAIN_USER_APP_UID = MAIN_USER_ID * PER_USER_UID_RANGE;
     69     private final int MANAGED_PROFILE_APP_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE;
     70 
     71     @Mock
     72     private UserManager mUserManager;
     73     @Mock
     74     private PackageManagerWrapper mPackageManager;
     75 
     76     private List<UserAppInfo> mInstalledAppList = Collections.emptyList();
     77 
     78     @Before
     79     public void setUp() {
     80         MockitoAnnotations.initMocks(this);
     81     }
     82 
     83     private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) {
     84         when(mPackageManager.queryIntentActivitiesAsUser(
     85                 argThat(isLaunchIntentFor(packageName)),
     86                 eq(PackageManager.GET_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE
     87                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE),
     88                 eq(userId))).thenReturn(launchable
     89                         ? Collections.singletonList(new ResolveInfo())
     90                         : Collections.emptyList());
     91     }
     92 
     93     @Test
     94     public void testCountInstalledAppsAcrossAllUsers() {
     95         // There are two users.
     96         when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
     97                 new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
     98                 new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0)));
     99 
    100         // The first user has four apps installed:
    101         // * app1 is an updated system app. It should be listed.
    102         // * app2 is a user-installed app. It should be listed.
    103         // * app3 is a system app that provides a launcher icon. It should be listed.
    104         // * app4 is a system app that provides no launcher icon. It should not be listed.
    105         when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
    106                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
    107                 | PackageManager.MATCH_ANY_USER,
    108                 MAIN_USER_ID)).thenReturn(Arrays.asList(
    109                         buildInfo(MAIN_USER_APP_UID, APP_1,
    110                                 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */),
    111                         buildInfo(MAIN_USER_APP_UID, APP_2, 0 /* flags */,
    112                                 0 /* targetSdkVersion */),
    113                         buildInfo(MAIN_USER_APP_UID, APP_3, ApplicationInfo.FLAG_SYSTEM,
    114                                 0 /* targetSdkVersion */),
    115                         buildInfo(MAIN_USER_APP_UID, APP_4, ApplicationInfo.FLAG_SYSTEM,
    116                                 0 /* targetSdkVersion */)));
    117         // For system apps, InstalledAppLister checks whether they handle the default launcher
    118         // intent to decide whether to include them in the list of installed apps or not.
    119         expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
    120         expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */);
    121 
    122         // app1, app3 and app4 are installed by enterprise policy.
    123         final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
    124         when(mPackageManager.getInstallReason(APP_1, mainUser))
    125                 .thenReturn(PackageManager.INSTALL_REASON_POLICY);
    126         when(mPackageManager.getInstallReason(APP_2, mainUser))
    127                 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
    128         when(mPackageManager.getInstallReason(APP_3, mainUser))
    129                 .thenReturn(PackageManager.INSTALL_REASON_POLICY);
    130         when(mPackageManager.getInstallReason(APP_4, mainUser))
    131                 .thenReturn(PackageManager.INSTALL_REASON_POLICY);
    132 
    133         // The second user has two apps installed:
    134         // * app5 is a user-installed app. It should be listed.
    135         // * app6 is a system app that provides a launcher icon. It should be listed.
    136         when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
    137                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
    138                 MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
    139                         buildInfo(MANAGED_PROFILE_APP_UID, APP_5, 0 /* flags */,
    140                                 0 /* targetSdkVersion */),
    141                         buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM,
    142                                 0 /* targetSdkVersion */)));
    143         expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
    144 
    145         // app5 is installed by enterprise policy.
    146         final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
    147         when(mPackageManager.getInstallReason(APP_5, managedProfileUser))
    148                 .thenReturn(PackageManager.INSTALL_REASON_POLICY);
    149         when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
    150                 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
    151 
    152         // List apps, considering apps installed by enterprise policy only.
    153         mInstalledAppList = Collections.emptyList();
    154         final InstalledAppListerTestable counter = new InstalledAppListerTestable();
    155         counter.execute();
    156         // Wait for the background task to finish.
    157         ShadowApplication.runBackgroundTasks();
    158 
    159         assertThat(mInstalledAppList.size()).isEqualTo(3);
    160 
    161         assertThat(checkAppFound(mInstalledAppList, APP_1, MAIN_USER_ID)).isTrue();
    162         assertThat(checkAppFound(mInstalledAppList, APP_2, MAIN_USER_ID)).isFalse();
    163         assertThat(checkAppFound(mInstalledAppList, APP_3, MAIN_USER_ID)).isTrue();
    164         assertThat(checkAppFound(mInstalledAppList, APP_4, MAIN_USER_ID)).isFalse();
    165         assertThat(checkAppFound(mInstalledAppList, APP_5, MANAGED_PROFILE_ID)).isTrue();
    166         assertThat(checkAppFound(mInstalledAppList, APP_6, MANAGED_PROFILE_ID)).isFalse();
    167 
    168         // Verify that installed packages were retrieved for the current user and the user's
    169         // managed profile.
    170         verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
    171         verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MANAGED_PROFILE_ID));
    172         verify(mPackageManager, atLeast(0))
    173             .queryIntentActivitiesAsUser(anyObject(), anyInt(), anyInt());
    174     }
    175 
    176     public static boolean checkAppFound(List<UserAppInfo> mInstalledAppList, String appId,
    177             int userId) {
    178        for (UserAppInfo info : mInstalledAppList) {
    179            if (appId.equals(info.appInfo.packageName) && (info.userInfo.id == userId)) {
    180                 return true;
    181             }
    182         }
    183         return false;
    184     }
    185 
    186     public static void verifyListUniqueness(List<UserAppInfo> list) {
    187         assertThat((new HashSet<>(list)).size()).isEqualTo(list.size());
    188     }
    189 
    190     private class InstalledAppListerTestable extends InstalledAppLister {
    191         public InstalledAppListerTestable() {
    192             super(mPackageManager, mUserManager);
    193         }
    194 
    195         @Override
    196         protected void onAppListBuilt(List<UserAppInfo> list) {
    197             mInstalledAppList = list;
    198         }
    199     }
    200 
    201     private static ArgumentMatcher<Intent> isLaunchIntentFor(String packageName) {
    202         return intent -> {
    203             if (intent == null) {
    204                 return false;
    205             }
    206             if (!Intent.ACTION_MAIN.equals(intent.getAction())) {
    207                 return false;
    208             }
    209             final Set<String> categories = intent.getCategories();
    210             if (categories == null || categories.size() != 1 ||
    211                     !categories.contains(Intent.CATEGORY_LAUNCHER)) {
    212                 return false;
    213             }
    214             if (!packageName.equals(intent.getPackage())) {
    215                 return false;
    216             }
    217             return true;
    218         };
    219     }
    220 }
    221