blob: 487558f81e4518ade57765bfb848032d3b0692cc [file] [log] [blame]
Makoto Onuki31459242016-03-22 11:12:18 -07001/*
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;
Makoto Onuki0acbb142016-03-22 17:02:57 -070022import android.util.Slog;
Makoto Onuki31459242016-03-22 11:12:18 -070023
Makoto Onukid99c6f02016-03-28 11:02:54 -070024import com.android.internal.util.Preconditions;
25
Makoto Onuki31459242016-03-22 11:12:18 -070026import 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;
Makoto Onuki9da23fc2016-03-29 11:14:42 -070034import java.util.function.Consumer;
Makoto Onuki31459242016-03-22 11:12:18 -070035
36/**
37 * User information used by {@link ShortcutService}.
38 */
39class ShortcutUser {
40 private static final String TAG = ShortcutService.TAG;
41
42 static final String TAG_ROOT = "user";
43 private static final String TAG_LAUNCHER = "launcher";
44
45 private static final String ATTR_VALUE = "value";
46
Makoto Onukid99c6f02016-03-28 11:02:54 -070047 static final class PackageWithUser {
48 final int userId;
49 final String packageName;
50
51 private PackageWithUser(int userId, String packageName) {
52 this.userId = userId;
53 this.packageName = Preconditions.checkNotNull(packageName);
54 }
55
56 public static PackageWithUser of(int launcherUserId, String packageName) {
57 return new PackageWithUser(launcherUserId, packageName);
58 }
59
Makoto Onuki9da23fc2016-03-29 11:14:42 -070060 public static PackageWithUser of(ShortcutPackageItem spi) {
61 return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
62 }
63
Makoto Onukid99c6f02016-03-28 11:02:54 -070064 @Override
65 public int hashCode() {
66 return packageName.hashCode() ^ userId;
67 }
68
69 @Override
70 public boolean equals(Object obj) {
71 if (!(obj instanceof PackageWithUser)) {
72 return false;
73 }
74 final PackageWithUser that = (PackageWithUser) obj;
75
76 return userId == that.userId && packageName.equals(that.packageName);
77 }
78
79 @Override
80 public String toString() {
81 return String.format("{Launcher: %d, %s}", userId, packageName);
82 }
83 }
84
Makoto Onuki31459242016-03-22 11:12:18 -070085 @UserIdInt
86 final int mUserId;
87
88 private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
89
Makoto Onukid99c6f02016-03-28 11:02:54 -070090 private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
Makoto Onuki31459242016-03-22 11:12:18 -070091
92 private ComponentName mLauncherComponent;
93
94 public ShortcutUser(int userId) {
95 mUserId = userId;
96 }
97
98 public ArrayMap<String, ShortcutPackage> getPackages() {
99 return mPackages;
100 }
101
Makoto Onukid99c6f02016-03-28 11:02:54 -0700102 public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
Makoto Onuki31459242016-03-22 11:12:18 -0700103 return mLaunchers;
104 }
105
Makoto Onukid99c6f02016-03-28 11:02:54 -0700106 public void addLauncher(ShortcutLauncher launcher) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700107 mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
108 launcher.getPackageName()), launcher);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700109 }
110
111 public ShortcutLauncher removeLauncher(
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700112 @UserIdInt int packageUserId, @NonNull String packageName) {
113 return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
Makoto Onukid99c6f02016-03-28 11:02:54 -0700114 }
115
Makoto Onuki31459242016-03-22 11:12:18 -0700116 public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
117 ShortcutPackage ret = mPackages.get(packageName);
118 if (ret == null) {
119 ret = new ShortcutPackage(mUserId, packageName);
120 mPackages.put(packageName, ret);
121 }
122 return ret;
123 }
124
Makoto Onukid99c6f02016-03-28 11:02:54 -0700125 public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
126 @UserIdInt int launcherUserId) {
127 final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
128 ShortcutLauncher ret = mLaunchers.get(key);
Makoto Onuki31459242016-03-22 11:12:18 -0700129 if (ret == null) {
Makoto Onukid99c6f02016-03-28 11:02:54 -0700130 ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
131 mLaunchers.put(key, ret);
Makoto Onuki31459242016-03-22 11:12:18 -0700132 }
133 return ret;
134 }
135
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700136 public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) {
137 {
138 final int size = mLaunchers.size();
139 for (int i = 0; i < size; i++) {
140 callback.accept(mLaunchers.valueAt(i));
141 }
142 }
143 {
144 final int size = mPackages.size();
145 for (int i = 0; i < size; i++) {
146 callback.accept(mPackages.valueAt(i));
147 }
148 }
149 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700150
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700151 public void unshadowPackage(ShortcutService s, @NonNull String packageName,
152 @UserIdInt int packageUserId) {
153 forPackageItem(packageName, packageUserId, spi -> {
154 Slog.i(TAG, String.format("Restoring for %s, user=%d", packageName, packageUserId));
155 spi.ensureNotShadowAndSave(s);
156 });
157 }
158
159 public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
160 Consumer<ShortcutPackageItem> callback) {
161 forAllPackageItems(spi -> {
162 if ((spi.getPackageUserId() == packageUserId)
163 && spi.getPackageName().equals(packageName)) {
164 callback.accept(spi);
165 }
166 });
Makoto Onuki0acbb142016-03-22 17:02:57 -0700167 }
168
169 public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
170 throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700171 out.startTag(null, TAG_ROOT);
172
173 ShortcutService.writeTagValue(out, TAG_LAUNCHER,
174 mLauncherComponent);
175
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700176 // Can't use forEachPackageItem due to the checked exceptions.
Makoto Onuki0acbb142016-03-22 17:02:57 -0700177 {
178 final int size = mLaunchers.size();
179 for (int i = 0; i < size; i++) {
180 saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
181 }
182 }
183 {
184 final int size = mPackages.size();
185 for (int i = 0; i < size; i++) {
186 saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
187 }
Makoto Onuki31459242016-03-22 11:12:18 -0700188 }
189
190 out.endTag(null, TAG_ROOT);
191 }
192
Makoto Onuki0acbb142016-03-22 17:02:57 -0700193 private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
194 ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700195 if (forBackup) {
196 if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
197 return; // Don't save.
198 }
199 if (spi.getPackageUserId() != spi.getOwnerUserId()) {
200 return; // Don't save cross-user information.
201 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700202 }
203 spi.saveToXml(out, forBackup);
204 }
205
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700206 public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
207 boolean fromBackup) throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700208 final ShortcutUser ret = new ShortcutUser(userId);
209
210 final int outerDepth = parser.getDepth();
211 int type;
212 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
213 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
214 if (type != XmlPullParser.START_TAG) {
215 continue;
216 }
217 final int depth = parser.getDepth();
218 final String tag = parser.getName();
Makoto Onuki31459242016-03-22 11:12:18 -0700219
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700220 if (depth == outerDepth + 1) {
221 switch (tag) {
222 case TAG_LAUNCHER: {
223 ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
224 parser, ATTR_VALUE);
225 continue;
226 }
227 case ShortcutPackage.TAG_ROOT: {
228 final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
229 s, parser, userId, fromBackup);
Makoto Onuki31459242016-03-22 11:12:18 -0700230
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700231 // Don't use addShortcut(), we don't need to save the icon.
232 ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
233 continue;
234 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700235
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700236 case ShortcutLauncher.TAG_ROOT: {
237 ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup));
238 continue;
239 }
Makoto Onuki31459242016-03-22 11:12:18 -0700240 }
241 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700242 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki31459242016-03-22 11:12:18 -0700243 }
244 return ret;
245 }
246
247 public ComponentName getLauncherComponent() {
248 return mLauncherComponent;
249 }
250
251 public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) {
252 if (Objects.equal(mLauncherComponent, launcherComponent)) {
253 return;
254 }
255 mLauncherComponent = launcherComponent;
256 s.scheduleSaveUser(mUserId);
257 }
258
259 public void resetThrottling() {
260 for (int i = mPackages.size() - 1; i >= 0; i--) {
261 mPackages.valueAt(i).resetThrottling();
262 }
263 }
264
265 public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
266 pw.print(prefix);
267 pw.print("User: ");
268 pw.print(mUserId);
269 pw.println();
270
271 pw.print(prefix);
272 pw.print(" ");
273 pw.print("Default launcher: ");
274 pw.print(mLauncherComponent);
275 pw.println();
276
277 for (int i = 0; i < mLaunchers.size(); i++) {
278 mLaunchers.valueAt(i).dump(s, pw, prefix + " ");
279 }
280
281 for (int i = 0; i < mPackages.size(); i++) {
282 mPackages.valueAt(i).dump(s, pw, prefix + " ");
283 }
Makoto Onuki31459242016-03-22 11:12:18 -0700284 }
285}