ShortcutUser.java revision d99c6f04bbb68f8be78f2c3ca625a3a8d5645275
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 */
16package com.android.server.pm;
17
18import android.annotation.NonNull;
19import android.annotation.UserIdInt;
20import android.content.ComponentName;
21import android.util.ArrayMap;
22import android.util.Slog;
23
24import com.android.internal.util.Preconditions;
25
26import libcore.util.Objects;
27
28import org.xmlpull.v1.XmlPullParser;
29import org.xmlpull.v1.XmlPullParserException;
30import org.xmlpull.v1.XmlSerializer;
31
32import java.io.IOException;
33import java.io.PrintWriter;
34
35/**
36 * User information used by {@link ShortcutService}.
37 */
38class ShortcutUser {
39    private static final String TAG = ShortcutService.TAG;
40
41    static final String TAG_ROOT = "user";
42    private static final String TAG_LAUNCHER = "launcher";
43
44    private static final String ATTR_VALUE = "value";
45
46    static final class PackageWithUser {
47        final int userId;
48        final String packageName;
49
50        private PackageWithUser(int userId, String packageName) {
51            this.userId = userId;
52            this.packageName = Preconditions.checkNotNull(packageName);
53        }
54
55        public static PackageWithUser of(int launcherUserId, String packageName) {
56            return new PackageWithUser(launcherUserId, packageName);
57        }
58
59        @Override
60        public int hashCode() {
61            return packageName.hashCode() ^ userId;
62        }
63
64        @Override
65        public boolean equals(Object obj) {
66            if (!(obj instanceof PackageWithUser)) {
67                return false;
68            }
69            final PackageWithUser that = (PackageWithUser) obj;
70
71            return userId == that.userId && packageName.equals(that.packageName);
72        }
73
74        @Override
75        public String toString() {
76            return String.format("{Launcher: %d, %s}", userId, packageName);
77        }
78    }
79
80    @UserIdInt
81    final int mUserId;
82
83    private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
84
85    private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
86
87    private final ArrayMap<PackageWithUser, ShortcutPackageInfo> mPackageInfos = new ArrayMap<>();
88
89    private ComponentName mLauncherComponent;
90
91    public ShortcutUser(int userId) {
92        mUserId = userId;
93    }
94
95    public ArrayMap<String, ShortcutPackage> getPackages() {
96        return mPackages;
97    }
98
99    public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
100        return mLaunchers;
101    }
102
103    public ShortcutLauncher getLauncher(@UserIdInt int userId, @NonNull String packageName) {
104        return mLaunchers.get(PackageWithUser.of(userId, packageName));
105    }
106
107    public void addLauncher(ShortcutLauncher launcher) {
108        mLaunchers.put(PackageWithUser.of(launcher.getUserId(), launcher.getPackageName()),
109                launcher);
110    }
111
112    public ShortcutLauncher removeLauncher(
113            @UserIdInt int userId, @NonNull String packageName) {
114        return mLaunchers.remove(PackageWithUser.of(userId, packageName));
115    }
116
117    public ArrayMap<PackageWithUser, ShortcutPackageInfo> getAllPackageInfos() {
118        return mPackageInfos;
119    }
120
121    public ShortcutPackageInfo getPackageInfo(@UserIdInt int userId, @NonNull String packageName) {
122        return mPackageInfos.get(PackageWithUser.of(userId, packageName));
123    }
124
125    public void addPackageInfo(ShortcutPackageInfo spi) {
126        mPackageInfos.put(PackageWithUser.of(spi.getUserId(), spi.getPackageName()), spi);
127    }
128
129    public ShortcutPackageInfo removePackageInfo(
130            @UserIdInt int userId, @NonNull String packageName) {
131        return mPackageInfos.remove(PackageWithUser.of(userId, packageName));
132    }
133
134    public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
135        ShortcutPackage ret = mPackages.get(packageName);
136        if (ret == null) {
137            ret = new ShortcutPackage(mUserId, packageName);
138            mPackages.put(packageName, ret);
139        }
140        return ret;
141    }
142
143    public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
144            @UserIdInt int launcherUserId) {
145        final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
146        ShortcutLauncher ret = mLaunchers.get(key);
147        if (ret == null) {
148            ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
149            mLaunchers.put(key, ret);
150        }
151        return ret;
152    }
153
154    public void ensurePackageInfo(ShortcutService s, String packageName, @UserIdInt int userId) {
155        final PackageWithUser key = PackageWithUser.of(userId, packageName);
156        final ShortcutPackageInfo existing = mPackageInfos.get(key);
157
158        if (existing != null) {
159            return;
160        }
161        if (ShortcutService.DEBUG) {
162            Slog.d(TAG, String.format("Fetching package info: %s user=%d", packageName, userId));
163        }
164        final ShortcutPackageInfo newSpi = ShortcutPackageInfo.generateForInstalledPackage(
165                s, packageName, userId);
166        mPackageInfos.put(key, newSpi);
167        s.scheduleSaveUser(mUserId);
168    }
169
170    public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
171            throws IOException, XmlPullParserException {
172        out.startTag(null, TAG_ROOT);
173
174        ShortcutService.writeTagValue(out, TAG_LAUNCHER,
175                mLauncherComponent);
176
177        {
178            final int size = mPackageInfos.size();
179            for (int i = 0; i < size; i++) {
180                saveShortcutPackageItem(s, out, mPackageInfos.valueAt(i), forBackup);
181            }
182        }
183        {
184            final int size = mLaunchers.size();
185            for (int i = 0; i < size; i++) {
186                saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
187            }
188        }
189        {
190            final int size = mPackages.size();
191            for (int i = 0; i < size; i++) {
192                saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
193            }
194        }
195
196        out.endTag(null, TAG_ROOT);
197    }
198
199    private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
200            ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
201        if (forBackup && !s.shouldBackupApp(spi.getPackageName(), mUserId)) {
202            return; // Don't save.
203        }
204        spi.saveToXml(out, forBackup);
205    }
206
207    public static ShortcutUser loadFromXml(XmlPullParser parser, int userId)
208            throws IOException, XmlPullParserException {
209        final ShortcutUser ret = new ShortcutUser(userId);
210
211        final int outerDepth = parser.getDepth();
212        int type;
213        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
214                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
215            if (type != XmlPullParser.START_TAG) {
216                continue;
217            }
218            final int depth = parser.getDepth();
219            final String tag = parser.getName();
220            switch (tag) {
221                case TAG_LAUNCHER: {
222                    ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
223                            parser, ATTR_VALUE);
224                    continue;
225                }
226                case ShortcutPackage.TAG_ROOT: {
227                    final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(parser, userId);
228
229                    // Don't use addShortcut(), we don't need to save the icon.
230                    ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
231                    continue;
232                }
233
234                case ShortcutLauncher.TAG_ROOT: {
235                    ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId));
236                    continue;
237                }
238
239                case ShortcutPackageInfo.TAG_ROOT: {
240                    ret.addPackageInfo(ShortcutPackageInfo.loadFromXml(parser, userId));
241                    continue;
242                }
243            }
244            throw ShortcutService.throwForInvalidTag(depth, tag);
245        }
246        return ret;
247    }
248
249    public ComponentName getLauncherComponent() {
250        return mLauncherComponent;
251    }
252
253    public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) {
254        if (Objects.equal(mLauncherComponent, launcherComponent)) {
255            return;
256        }
257        mLauncherComponent = launcherComponent;
258        s.scheduleSaveUser(mUserId);
259    }
260
261    public void resetThrottling() {
262        for (int i = mPackages.size() - 1; i >= 0; i--) {
263            mPackages.valueAt(i).resetThrottling();
264        }
265    }
266
267    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
268        pw.print(prefix);
269        pw.print("User: ");
270        pw.print(mUserId);
271        pw.println();
272
273        pw.print(prefix);
274        pw.print("  ");
275        pw.print("Default launcher: ");
276        pw.print(mLauncherComponent);
277        pw.println();
278
279        for (int i = 0; i < mLaunchers.size(); i++) {
280            mLaunchers.valueAt(i).dump(s, pw, prefix + "  ");
281        }
282
283        for (int i = 0; i < mPackages.size(); i++) {
284            mPackages.valueAt(i).dump(s, pw, prefix + "  ");
285        }
286
287        for (int i = 0; i < mPackageInfos.size(); i++) {
288            mPackageInfos.valueAt(i).dump(s, pw, prefix + "  ");
289        }
290    }
291}
292