1/*
2 * Copyright (C) 2012 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
17package android.content.pm;
18
19import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
21import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
22import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
23import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
24import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
25import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
26import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
27import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
28import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
29
30import android.util.ArraySet;
31
32import com.android.internal.util.ArrayUtils;
33
34import java.util.Arrays;
35
36/**
37 * Per-user state information about a package.
38 * @hide
39 */
40public class PackageUserState {
41    public long ceDataInode;
42    public boolean installed;
43    public boolean stopped;
44    public boolean notLaunched;
45    public boolean hidden; // Is the app restricted by owner / admin
46    public boolean suspended;
47    public boolean instantApp;
48    public boolean virtualPreload;
49    public int enabled;
50    public String lastDisableAppCaller;
51    public int domainVerificationStatus;
52    public int appLinkGeneration;
53    public int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
54    public int installReason;
55
56    public ArraySet<String> disabledComponents;
57    public ArraySet<String> enabledComponents;
58
59    public String[] overlayPaths;
60
61    public PackageUserState() {
62        installed = true;
63        hidden = false;
64        suspended = false;
65        enabled = COMPONENT_ENABLED_STATE_DEFAULT;
66        domainVerificationStatus =
67                PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
68        installReason = PackageManager.INSTALL_REASON_UNKNOWN;
69    }
70
71    public PackageUserState(PackageUserState o) {
72        ceDataInode = o.ceDataInode;
73        installed = o.installed;
74        stopped = o.stopped;
75        notLaunched = o.notLaunched;
76        hidden = o.hidden;
77        suspended = o.suspended;
78        instantApp = o.instantApp;
79        virtualPreload = o.virtualPreload;
80        enabled = o.enabled;
81        lastDisableAppCaller = o.lastDisableAppCaller;
82        domainVerificationStatus = o.domainVerificationStatus;
83        appLinkGeneration = o.appLinkGeneration;
84        categoryHint = o.categoryHint;
85        installReason = o.installReason;
86        disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
87        enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
88        overlayPaths =
89            o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
90    }
91
92    /**
93     * Test if this package is installed.
94     */
95    public boolean isAvailable(int flags) {
96        // True if it is installed for this user and it is not hidden. If it is hidden,
97        // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
98        final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
99        final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
100        return matchAnyUser
101                || (this.installed
102                        && (!this.hidden || matchUninstalled));
103    }
104
105    /**
106     * Test if the given component is considered installed, enabled and a match
107     * for the given flags.
108     *
109     * <p>
110     * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
111     * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
112     * </p>
113     */
114    public boolean isMatch(ComponentInfo componentInfo, int flags) {
115        final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
116        final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
117        if (!isAvailable(flags)
118                && !(isSystemApp && matchUninstalled)) return false;
119        if (!isEnabled(componentInfo, flags)) return false;
120
121        if ((flags & MATCH_SYSTEM_ONLY) != 0) {
122            if (!isSystemApp) {
123                return false;
124            }
125        }
126
127        final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
128                && !componentInfo.directBootAware;
129        final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
130                && componentInfo.directBootAware;
131        return matchesUnaware || matchesAware;
132    }
133
134    /**
135     * Test if the given component is considered enabled.
136     */
137    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
138        if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
139            return true;
140        }
141
142        // First check if the overall package is disabled; if the package is
143        // enabled then fall through to check specific component
144        switch (this.enabled) {
145            case COMPONENT_ENABLED_STATE_DISABLED:
146            case COMPONENT_ENABLED_STATE_DISABLED_USER:
147                return false;
148            case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
149                if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
150                    return false;
151                }
152            case COMPONENT_ENABLED_STATE_DEFAULT:
153                if (!componentInfo.applicationInfo.enabled) {
154                    return false;
155                }
156            case COMPONENT_ENABLED_STATE_ENABLED:
157                break;
158        }
159
160        // Check if component has explicit state before falling through to
161        // the manifest default
162        if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
163            return true;
164        }
165        if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
166            return false;
167        }
168
169        return componentInfo.enabled;
170    }
171
172    @Override
173    final public boolean equals(Object obj) {
174        if (!(obj instanceof PackageUserState)) {
175            return false;
176        }
177        final PackageUserState oldState = (PackageUserState) obj;
178        if (ceDataInode != oldState.ceDataInode) {
179            return false;
180        }
181        if (installed != oldState.installed) {
182            return false;
183        }
184        if (stopped != oldState.stopped) {
185            return false;
186        }
187        if (notLaunched != oldState.notLaunched) {
188            return false;
189        }
190        if (hidden != oldState.hidden) {
191            return false;
192        }
193        if (suspended != oldState.suspended) {
194            return false;
195        }
196        if (instantApp != oldState.instantApp) {
197            return false;
198        }
199        if (virtualPreload != oldState.virtualPreload) {
200            return false;
201        }
202        if (enabled != oldState.enabled) {
203            return false;
204        }
205        if ((lastDisableAppCaller == null && oldState.lastDisableAppCaller != null)
206                || (lastDisableAppCaller != null
207                        && !lastDisableAppCaller.equals(oldState.lastDisableAppCaller))) {
208            return false;
209        }
210        if (domainVerificationStatus != oldState.domainVerificationStatus) {
211            return false;
212        }
213        if (appLinkGeneration != oldState.appLinkGeneration) {
214            return false;
215        }
216        if (categoryHint != oldState.categoryHint) {
217            return false;
218        }
219        if (installReason != oldState.installReason) {
220            return false;
221        }
222        if ((disabledComponents == null && oldState.disabledComponents != null)
223                || (disabledComponents != null && oldState.disabledComponents == null)) {
224            return false;
225        }
226        if (disabledComponents != null) {
227            if (disabledComponents.size() != oldState.disabledComponents.size()) {
228                return false;
229            }
230            for (int i = disabledComponents.size() - 1; i >=0; --i) {
231                if (!oldState.disabledComponents.contains(disabledComponents.valueAt(i))) {
232                    return false;
233                }
234            }
235        }
236        if ((enabledComponents == null && oldState.enabledComponents != null)
237                || (enabledComponents != null && oldState.enabledComponents == null)) {
238            return false;
239        }
240        if (enabledComponents != null) {
241            if (enabledComponents.size() != oldState.enabledComponents.size()) {
242                return false;
243            }
244            for (int i = enabledComponents.size() - 1; i >=0; --i) {
245                if (!oldState.enabledComponents.contains(enabledComponents.valueAt(i))) {
246                    return false;
247                }
248            }
249        }
250        return true;
251    }
252}
253