blob: 76d47a839f90c1089c24931524ebe63438379955 [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.pm.ShortcutInfo;
21import android.util.ArrayMap;
22import android.util.ArraySet;
Makoto Onuki2e210c42016-03-30 08:30:36 -070023import android.util.Slog;
24
25import com.android.internal.annotations.VisibleForTesting;
26import com.android.server.pm.ShortcutUser.PackageWithUser;
Makoto Onuki31459242016-03-22 11:12:18 -070027
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 Onuki2e210c42016-03-30 08:30:36 -070034import java.util.ArrayList;
Makoto Onuki31459242016-03-22 11:12:18 -070035import java.util.List;
36
37/**
38 * Launcher information used by {@link ShortcutService}.
39 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -070040class ShortcutLauncher extends ShortcutPackageItem {
Makoto Onuki31459242016-03-22 11:12:18 -070041 private static final String TAG = ShortcutService.TAG;
42
43 static final String TAG_ROOT = "launcher-pins";
44
45 private static final String TAG_PACKAGE = "package";
46 private static final String TAG_PIN = "pin";
47
Makoto Onukid99c6f02016-03-28 11:02:54 -070048 private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
Makoto Onuki31459242016-03-22 11:12:18 -070049 private static final String ATTR_VALUE = "value";
50 private static final String ATTR_PACKAGE_NAME = "package-name";
Makoto Onuki2e210c42016-03-30 08:30:36 -070051 private static final String ATTR_PACKAGE_USER_ID = "package-user";
Makoto Onuki31459242016-03-22 11:12:18 -070052
Makoto Onuki9da23fc2016-03-29 11:14:42 -070053 private final int mOwnerUserId;
Makoto Onukid99c6f02016-03-28 11:02:54 -070054
Makoto Onuki31459242016-03-22 11:12:18 -070055 /**
56 * Package name -> IDs.
57 */
Makoto Onuki2e210c42016-03-30 08:30:36 -070058 final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
Makoto Onuki31459242016-03-22 11:12:18 -070059
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070060 private ShortcutLauncher(@NonNull ShortcutUser shortcutUser,
61 @UserIdInt int ownerUserId, @NonNull String packageName,
Makoto Onuki9da23fc2016-03-29 11:14:42 -070062 @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070063 super(shortcutUser, launcherUserId, packageName,
64 spi != null ? spi : ShortcutPackageInfo.newEmpty());
Makoto Onuki9da23fc2016-03-29 11:14:42 -070065 mOwnerUserId = ownerUserId;
66 }
67
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070068 public ShortcutLauncher(@NonNull ShortcutUser shortcutUser,
69 @UserIdInt int ownerUserId, @NonNull String packageName,
Makoto Onukid99c6f02016-03-28 11:02:54 -070070 @UserIdInt int launcherUserId) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070071 this(shortcutUser, ownerUserId, packageName, launcherUserId, null);
Makoto Onuki31459242016-03-22 11:12:18 -070072 }
73
Makoto Onuki9da23fc2016-03-29 11:14:42 -070074 @Override
75 public int getOwnerUserId() {
76 return mOwnerUserId;
Makoto Onuki0acbb142016-03-22 17:02:57 -070077 }
78
Makoto Onuki2e210c42016-03-30 08:30:36 -070079 /**
80 * Called when the new package can't receive the backup, due to signature or version mismatch.
81 */
82 @Override
83 protected void onRestoreBlocked(ShortcutService s) {
84 final ArrayList<PackageWithUser> pinnedPackages =
85 new ArrayList<>(mPinnedShortcuts.keySet());
86 mPinnedShortcuts.clear();
87 for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
88 final PackageWithUser pu = pinnedPackages.get(i);
89 s.getPackageShortcutsLocked(pu.packageName, pu.userId)
90 .refreshPinnedFlags(s);
91 }
92 }
93
94 @Override
95 protected void onRestored(ShortcutService s) {
96 // Nothing to do.
97 }
98
Makoto Onuki9da23fc2016-03-29 11:14:42 -070099 public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
100 @NonNull String packageName, @NonNull List<String> ids) {
101 final ShortcutPackage packageShortcuts =
102 s.getPackageShortcutsLocked(packageName, packageUserId);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700103
Makoto Onuki2e210c42016-03-30 08:30:36 -0700104 final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
105
Makoto Onuki31459242016-03-22 11:12:18 -0700106 final int idSize = ids.size();
107 if (idSize == 0) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700108 mPinnedShortcuts.remove(pu);
Makoto Onuki31459242016-03-22 11:12:18 -0700109 } else {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700110 final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
Makoto Onuki31459242016-03-22 11:12:18 -0700111
112 // Pin shortcuts. Make sure only pin the ones that were visible to the caller.
113 // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
114
Makoto Onuki31459242016-03-22 11:12:18 -0700115 final ArraySet<String> newSet = new ArraySet<>();
116
117 for (int i = 0; i < idSize; i++) {
118 final String id = ids.get(i);
119 final ShortcutInfo si = packageShortcuts.findShortcutById(id);
120 if (si == null) {
121 continue;
122 }
123 if (si.isDynamic() || (prevSet != null && prevSet.contains(id))) {
124 newSet.add(id);
125 }
126 }
Makoto Onuki2e210c42016-03-30 08:30:36 -0700127 mPinnedShortcuts.put(pu, newSet);
Makoto Onuki31459242016-03-22 11:12:18 -0700128 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700129 packageShortcuts.refreshPinnedFlags(s);
Makoto Onuki31459242016-03-22 11:12:18 -0700130 }
131
132 /**
133 * Return the pinned shortcut IDs for the publisher package.
134 */
Makoto Onuki2e210c42016-03-30 08:30:36 -0700135 public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
136 @UserIdInt int packageUserId) {
137 return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
Makoto Onuki31459242016-03-22 11:12:18 -0700138 }
139
Makoto Onuki2e210c42016-03-30 08:30:36 -0700140 boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
141 return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
Makoto Onuki31459242016-03-22 11:12:18 -0700142 }
143
144 /**
145 * Persist.
146 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700147 @Override
148 public void saveToXml(XmlSerializer out, boolean forBackup)
149 throws IOException {
Makoto Onuki31459242016-03-22 11:12:18 -0700150 final int size = mPinnedShortcuts.size();
151 if (size == 0) {
152 return; // Nothing to write.
153 }
154
155 out.startTag(null, TAG_ROOT);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700156 ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
157 ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
158 getPackageInfo().saveToXml(out);
Makoto Onuki31459242016-03-22 11:12:18 -0700159
160 for (int i = 0; i < size; i++) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700161 final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
162
163 if (forBackup && (pu.userId != getOwnerUserId())) {
164 continue; // Target package on a different user, skip. (i.e. work profile)
165 }
166
Makoto Onuki31459242016-03-22 11:12:18 -0700167 out.startTag(null, TAG_PACKAGE);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700168 ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
169 ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700170
171 final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
172 final int idSize = ids.size();
173 for (int j = 0; j < idSize; j++) {
174 ShortcutService.writeTagValue(out, TAG_PIN, ids.valueAt(j));
175 }
176 out.endTag(null, TAG_PACKAGE);
177 }
178
179 out.endTag(null, TAG_ROOT);
180 }
181
182 /**
183 * Load.
184 */
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700185 public static ShortcutLauncher loadFromXml(XmlPullParser parser, ShortcutUser shortcutUser,
186 int ownerUserId, boolean fromBackup) throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700187 final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
188 ATTR_PACKAGE_NAME);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700189
190 // If restoring, just use the real user ID.
191 final int launcherUserId =
192 fromBackup ? ownerUserId
193 : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700194
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700195 final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, launcherUserId,
196 launcherPackageName, launcherUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700197
198 ArraySet<String> ids = null;
199 final int outerDepth = parser.getDepth();
200 int type;
201 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
202 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
203 if (type != XmlPullParser.START_TAG) {
204 continue;
205 }
206 final int depth = parser.getDepth();
207 final String tag = parser.getName();
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700208 if (depth == outerDepth + 1) {
209 switch (tag) {
210 case ShortcutPackageInfo.TAG_ROOT:
Makoto Onuki2e210c42016-03-30 08:30:36 -0700211 ret.getPackageInfo().loadFromXml(parser, fromBackup);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700212 continue;
213 case TAG_PACKAGE: {
214 final String packageName = ShortcutService.parseStringAttribute(parser,
215 ATTR_PACKAGE_NAME);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700216 final int packageUserId = fromBackup ? ownerUserId
217 : ShortcutService.parseIntAttribute(parser,
218 ATTR_PACKAGE_USER_ID, ownerUserId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700219 ids = new ArraySet<>();
Makoto Onuki2e210c42016-03-30 08:30:36 -0700220 ret.mPinnedShortcuts.put(
221 PackageWithUser.of(packageUserId, packageName), ids);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700222 continue;
223 }
Makoto Onuki31459242016-03-22 11:12:18 -0700224 }
225 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700226 if (depth == outerDepth + 2) {
227 switch (tag) {
228 case TAG_PIN: {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700229 if (ids == null) {
230 Slog.w(TAG, TAG_PIN + " in invalid place");
231 } else {
232 ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
233 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700234 continue;
235 }
236 }
237 }
238 ShortcutService.warnForInvalidTag(depth, tag);
239 }
Makoto Onuki31459242016-03-22 11:12:18 -0700240 return ret;
241 }
242
243 public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
244 pw.println();
245
246 pw.print(prefix);
247 pw.print("Launcher: ");
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700248 pw.print(getPackageName());
249 pw.print(" Package user: ");
250 pw.print(getPackageUserId());
Makoto Onuki2e210c42016-03-30 08:30:36 -0700251 pw.print(" Owner user: ");
252 pw.print(getOwnerUserId());
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700253 pw.println();
254
255 getPackageInfo().dump(s, pw, prefix + " ");
Makoto Onuki31459242016-03-22 11:12:18 -0700256 pw.println();
257
258 final int size = mPinnedShortcuts.size();
259 for (int i = 0; i < size; i++) {
260 pw.println();
261
Makoto Onuki2e210c42016-03-30 08:30:36 -0700262 final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
263
Makoto Onuki31459242016-03-22 11:12:18 -0700264 pw.print(prefix);
265 pw.print(" ");
266 pw.print("Package: ");
Makoto Onuki2e210c42016-03-30 08:30:36 -0700267 pw.print(pu.packageName);
268 pw.print(" User: ");
269 pw.println(pu.userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700270
271 final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
272 final int idSize = ids.size();
273
274 for (int j = 0; j < idSize; j++) {
275 pw.print(prefix);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700276 pw.print(" Pinned: ");
Makoto Onuki31459242016-03-22 11:12:18 -0700277 pw.print(ids.valueAt(j));
278 pw.println();
279 }
280 }
281 }
Makoto Onuki2e210c42016-03-30 08:30:36 -0700282
283 @VisibleForTesting
284 ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
285 return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
286 }
Makoto Onuki31459242016-03-22 11:12:18 -0700287}