1 /*
2  * Copyright (C) 2019 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.server.testing.shadows;
18 
19 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20 import static android.content.pm.PackageManager.NameNotFoundException;
21 
22 import android.app.ApplicationPackageManager;
23 import android.content.Intent;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.ResolveInfo;
26 import android.os.UserHandle;
27 import android.util.ArrayMap;
28 
29 import org.robolectric.annotation.Implements;
30 import org.robolectric.annotation.Resetter;
31 
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 
37 /**
38  * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct
39  * package in user-specific invocations.
40  */
41 @Implements(value = ApplicationPackageManager.class)
42 public class ShadowApplicationPackageManager
43         extends org.robolectric.shadows.ShadowApplicationPackageManager {
44     private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
45     private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
46     private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
47     private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
48     private static final Map<String, Integer> sPackageAppEnabledStates = new ArrayMap<>();
49 
50     /**
51      * Registers the package {@code packageName} to be returned when invoking {@link
52      * ApplicationPackageManager#getPackageInfoAsUser(String, int, int)} and {@link
53      * ApplicationPackageManager#getInstalledPackagesAsUser(int, int)}.
54      */
addInstalledPackage(String packageName, PackageInfo packageInfo)55     public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
56         sPackageInfos.put(packageName, packageInfo);
57         sInstalledPackages.add(packageInfo);
58         sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
59     }
60 
61     /**
62      * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
63      * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
64      */
setPackageUid(String packageName, int packageUid)65     public static void setPackageUid(String packageName, int packageUid) {
66         sPackageUids.put(packageName, packageUid);
67     }
68 
69     /**
70      * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
71      * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
72      */
setPackageUidAsUser(String packageName, int packageUid, int userId)73     public static void setPackageUidAsUser(String packageName, int packageUid, int userId) {
74         final Map<String, Integer> userPackageUids =
75                 sUserPackageUids.containsKey(userId)
76                         ? sUserPackageUids.get(userId)
77                         : new HashMap<>();
78         userPackageUids.put(packageName, packageUid);
79         sUserPackageUids.put(userId, userPackageUids);
80     }
81 
82     @Override
getApplicationEnabledSetting(String packageName)83     protected int getApplicationEnabledSetting(String packageName) {
84         if (packageName.isEmpty()) {
85             throw new IllegalArgumentException("Robo: Package '' does not exist.");
86         }
87         if (!sPackageAppEnabledStates.containsKey(packageName)) {
88             return COMPONENT_ENABLED_STATE_DEFAULT;
89         }
90         return sPackageAppEnabledStates.get(packageName);
91     }
92 
93     @Override
setApplicationEnabledSetting(String packageName, int newState, int flags)94     protected void setApplicationEnabledSetting(String packageName, int newState, int flags) {
95         sPackageAppEnabledStates.put(packageName, Integer.valueOf(newState));  // flags unused here.
96     }
97 
98     @Override
getPackageInfoAsUser(String packageName, int flags, int userId)99     protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
100             throws NameNotFoundException {
101         if (!sPackageInfos.containsKey(packageName)) {
102             throw new NameNotFoundException(packageName);
103         }
104         return sPackageInfos.get(packageName);
105     }
106 
107     @Override
getInstalledPackagesAsUser(int flags, int userId)108     protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
109         return sInstalledPackages;
110     }
111 
112     @Override
getPackageUidAsUser(String packageName, int flags, int userId)113     protected int getPackageUidAsUser(String packageName, int flags, int userId)
114             throws NameNotFoundException {
115         if (sUserPackageUids.containsKey(userId)
116                 && sUserPackageUids.get(userId).containsKey(packageName)) {
117             return sUserPackageUids.get(userId).get(packageName);
118         }
119         if (!sPackageUids.containsKey(packageName)) {
120             throw new NameNotFoundException(packageName);
121         }
122         return sPackageUids.get(packageName);
123     }
124 
125     @Override
queryBroadcastReceiversAsUser( Intent intent, int flags, UserHandle userHandle)126     protected List<ResolveInfo> queryBroadcastReceiversAsUser(
127             Intent intent, int flags, UserHandle userHandle) {
128         // Currently does not handle multi-user.
129         return queryBroadcastReceivers(intent, flags);
130     }
131 
132     /** Clear package state. */
133     @Resetter
reset()134     public static void reset() {
135         sPackageInfos.clear();
136         sInstalledPackages.clear();
137         sPackageAppEnabledStates.clear();
138         org.robolectric.shadows.ShadowApplicationPackageManager.reset();
139     }
140 }
141