blob: 2af1bcb425ecac9df4586acb8ac1f4c06b73ea53 [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;
Makoto Onukic8c33292016-09-12 16:36:59 -070020import android.content.pm.PackageInfo;
Makoto Onuki31459242016-03-22 11:12:18 -070021import android.content.pm.ShortcutInfo;
22import android.util.ArrayMap;
23import android.util.ArraySet;
Makoto Onuki2e210c42016-03-30 08:30:36 -070024import android.util.Slog;
25
26import com.android.internal.annotations.VisibleForTesting;
27import com.android.server.pm.ShortcutUser.PackageWithUser;
Makoto Onuki31459242016-03-22 11:12:18 -070028
Makoto Onuki76269922016-07-15 14:58:54 -070029import org.json.JSONException;
30import org.json.JSONObject;
Makoto Onuki31459242016-03-22 11:12:18 -070031import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlPullParserException;
33import org.xmlpull.v1.XmlSerializer;
34
35import java.io.IOException;
36import java.io.PrintWriter;
Makoto Onuki2e210c42016-03-30 08:30:36 -070037import java.util.ArrayList;
Makoto Onuki31459242016-03-22 11:12:18 -070038import java.util.List;
39
40/**
41 * Launcher information used by {@link ShortcutService}.
Makoto Onuki22fcc682016-05-17 14:52:19 -070042 *
43 * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
Makoto Onuki31459242016-03-22 11:12:18 -070044 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -070045class ShortcutLauncher extends ShortcutPackageItem {
Makoto Onuki31459242016-03-22 11:12:18 -070046 private static final String TAG = ShortcutService.TAG;
47
48 static final String TAG_ROOT = "launcher-pins";
49
50 private static final String TAG_PACKAGE = "package";
51 private static final String TAG_PIN = "pin";
52
Makoto Onukid99c6f02016-03-28 11:02:54 -070053 private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
Makoto Onuki31459242016-03-22 11:12:18 -070054 private static final String ATTR_VALUE = "value";
55 private static final String ATTR_PACKAGE_NAME = "package-name";
Makoto Onuki2e210c42016-03-30 08:30:36 -070056 private static final String ATTR_PACKAGE_USER_ID = "package-user";
Makoto Onuki31459242016-03-22 11:12:18 -070057
Makoto Onuki9da23fc2016-03-29 11:14:42 -070058 private final int mOwnerUserId;
Makoto Onukid99c6f02016-03-28 11:02:54 -070059
Makoto Onuki31459242016-03-22 11:12:18 -070060 /**
61 * Package name -> IDs.
62 */
Makoto Onuki2e210c42016-03-30 08:30:36 -070063 final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
Makoto Onuki31459242016-03-22 11:12:18 -070064
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070065 private ShortcutLauncher(@NonNull ShortcutUser shortcutUser,
66 @UserIdInt int ownerUserId, @NonNull String packageName,
Makoto Onuki9da23fc2016-03-29 11:14:42 -070067 @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070068 super(shortcutUser, launcherUserId, packageName,
69 spi != null ? spi : ShortcutPackageInfo.newEmpty());
Makoto Onuki9da23fc2016-03-29 11:14:42 -070070 mOwnerUserId = ownerUserId;
71 }
72
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070073 public ShortcutLauncher(@NonNull ShortcutUser shortcutUser,
74 @UserIdInt int ownerUserId, @NonNull String packageName,
Makoto Onukid99c6f02016-03-28 11:02:54 -070075 @UserIdInt int launcherUserId) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070076 this(shortcutUser, ownerUserId, packageName, launcherUserId, null);
Makoto Onuki31459242016-03-22 11:12:18 -070077 }
78
Makoto Onuki9da23fc2016-03-29 11:14:42 -070079 @Override
80 public int getOwnerUserId() {
81 return mOwnerUserId;
Makoto Onuki0acbb142016-03-22 17:02:57 -070082 }
83
Makoto Onuki2e210c42016-03-30 08:30:36 -070084 /**
85 * Called when the new package can't receive the backup, due to signature or version mismatch.
86 */
87 @Override
Makoto Onukic51b2872016-05-04 15:24:50 -070088 protected void onRestoreBlocked() {
Makoto Onuki2e210c42016-03-30 08:30:36 -070089 final ArrayList<PackageWithUser> pinnedPackages =
90 new ArrayList<>(mPinnedShortcuts.keySet());
91 mPinnedShortcuts.clear();
92 for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
93 final PackageWithUser pu = pinnedPackages.get(i);
Makoto Onukic51b2872016-05-04 15:24:50 -070094 final ShortcutPackage p = mShortcutUser.getPackageShortcutsIfExists(pu.packageName);
95 if (p != null) {
96 p.refreshPinnedFlags();
97 }
Makoto Onuki2e210c42016-03-30 08:30:36 -070098 }
99 }
100
101 @Override
Makoto Onukic51b2872016-05-04 15:24:50 -0700102 protected void onRestored() {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700103 // Nothing to do.
104 }
105
Makoto Onukic51b2872016-05-04 15:24:50 -0700106 public void pinShortcuts(@UserIdInt int packageUserId,
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700107 @NonNull String packageName, @NonNull List<String> ids) {
108 final ShortcutPackage packageShortcuts =
Makoto Onukic51b2872016-05-04 15:24:50 -0700109 mShortcutUser.getPackageShortcutsIfExists(packageName);
110 if (packageShortcuts == null) {
111 return; // No need to instantiate.
112 }
Makoto Onukid99c6f02016-03-28 11:02:54 -0700113
Makoto Onuki2e210c42016-03-30 08:30:36 -0700114 final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
115
Makoto Onuki31459242016-03-22 11:12:18 -0700116 final int idSize = ids.size();
117 if (idSize == 0) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700118 mPinnedShortcuts.remove(pu);
Makoto Onuki31459242016-03-22 11:12:18 -0700119 } else {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700120 final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
Makoto Onuki31459242016-03-22 11:12:18 -0700121
122 // Pin shortcuts. Make sure only pin the ones that were visible to the caller.
123 // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
124
Makoto Onuki31459242016-03-22 11:12:18 -0700125 final ArraySet<String> newSet = new ArraySet<>();
126
127 for (int i = 0; i < idSize; i++) {
128 final String id = ids.get(i);
129 final ShortcutInfo si = packageShortcuts.findShortcutById(id);
130 if (si == null) {
131 continue;
132 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700133 if (si.isDynamic() || si.isManifestShortcut()
134 || (prevSet != null && prevSet.contains(id))) {
Makoto Onuki31459242016-03-22 11:12:18 -0700135 newSet.add(id);
136 }
137 }
Makoto Onuki2e210c42016-03-30 08:30:36 -0700138 mPinnedShortcuts.put(pu, newSet);
Makoto Onuki31459242016-03-22 11:12:18 -0700139 }
Makoto Onukic51b2872016-05-04 15:24:50 -0700140 packageShortcuts.refreshPinnedFlags();
Makoto Onuki31459242016-03-22 11:12:18 -0700141 }
142
143 /**
144 * Return the pinned shortcut IDs for the publisher package.
145 */
Makoto Onuki2e210c42016-03-30 08:30:36 -0700146 public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
147 @UserIdInt int packageUserId) {
148 return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
Makoto Onuki31459242016-03-22 11:12:18 -0700149 }
150
Makoto Onuki2e210c42016-03-30 08:30:36 -0700151 boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
152 return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
Makoto Onuki31459242016-03-22 11:12:18 -0700153 }
154
Makoto Onukic8c33292016-09-12 16:36:59 -0700155 public void ensureVersionInfo() {
156 final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(
157 getPackageName(), getPackageUserId());
158 if (pi == null) {
159 Slog.w(TAG, "Package not found: " + getPackageName());
160 return;
161 }
162 getPackageInfo().updateVersionInfo(pi);
163 }
164
Makoto Onuki31459242016-03-22 11:12:18 -0700165 /**
166 * Persist.
167 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700168 @Override
169 public void saveToXml(XmlSerializer out, boolean forBackup)
170 throws IOException {
Makoto Onuki31459242016-03-22 11:12:18 -0700171 final int size = mPinnedShortcuts.size();
172 if (size == 0) {
173 return; // Nothing to write.
174 }
175
176 out.startTag(null, TAG_ROOT);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700177 ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
178 ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
179 getPackageInfo().saveToXml(out);
Makoto Onuki31459242016-03-22 11:12:18 -0700180
181 for (int i = 0; i < size; i++) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700182 final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
183
184 if (forBackup && (pu.userId != getOwnerUserId())) {
185 continue; // Target package on a different user, skip. (i.e. work profile)
186 }
187
Makoto Onuki31459242016-03-22 11:12:18 -0700188 out.startTag(null, TAG_PACKAGE);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700189 ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
190 ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700191
192 final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
193 final int idSize = ids.size();
194 for (int j = 0; j < idSize; j++) {
195 ShortcutService.writeTagValue(out, TAG_PIN, ids.valueAt(j));
196 }
197 out.endTag(null, TAG_PACKAGE);
198 }
199
200 out.endTag(null, TAG_ROOT);
201 }
202
203 /**
204 * Load.
205 */
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700206 public static ShortcutLauncher loadFromXml(XmlPullParser parser, ShortcutUser shortcutUser,
207 int ownerUserId, boolean fromBackup) throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700208 final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
209 ATTR_PACKAGE_NAME);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700210
211 // If restoring, just use the real user ID.
212 final int launcherUserId =
213 fromBackup ? ownerUserId
214 : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700215
Makoto Onukic8c33292016-09-12 16:36:59 -0700216 final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, ownerUserId,
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700217 launcherPackageName, launcherUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700218
219 ArraySet<String> ids = null;
220 final int outerDepth = parser.getDepth();
221 int type;
222 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
223 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
224 if (type != XmlPullParser.START_TAG) {
225 continue;
226 }
227 final int depth = parser.getDepth();
228 final String tag = parser.getName();
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700229 if (depth == outerDepth + 1) {
230 switch (tag) {
231 case ShortcutPackageInfo.TAG_ROOT:
Makoto Onuki2e210c42016-03-30 08:30:36 -0700232 ret.getPackageInfo().loadFromXml(parser, fromBackup);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700233 continue;
234 case TAG_PACKAGE: {
235 final String packageName = ShortcutService.parseStringAttribute(parser,
236 ATTR_PACKAGE_NAME);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700237 final int packageUserId = fromBackup ? ownerUserId
238 : ShortcutService.parseIntAttribute(parser,
239 ATTR_PACKAGE_USER_ID, ownerUserId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700240 ids = new ArraySet<>();
Makoto Onuki2e210c42016-03-30 08:30:36 -0700241 ret.mPinnedShortcuts.put(
242 PackageWithUser.of(packageUserId, packageName), ids);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700243 continue;
244 }
Makoto Onuki31459242016-03-22 11:12:18 -0700245 }
246 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700247 if (depth == outerDepth + 2) {
248 switch (tag) {
249 case TAG_PIN: {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700250 if (ids == null) {
251 Slog.w(TAG, TAG_PIN + " in invalid place");
252 } else {
253 ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
254 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700255 continue;
256 }
257 }
258 }
259 ShortcutService.warnForInvalidTag(depth, tag);
260 }
Makoto Onuki31459242016-03-22 11:12:18 -0700261 return ret;
262 }
263
Makoto Onukic51b2872016-05-04 15:24:50 -0700264 public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
Makoto Onuki31459242016-03-22 11:12:18 -0700265 pw.println();
266
267 pw.print(prefix);
268 pw.print("Launcher: ");
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700269 pw.print(getPackageName());
270 pw.print(" Package user: ");
271 pw.print(getPackageUserId());
Makoto Onuki2e210c42016-03-30 08:30:36 -0700272 pw.print(" Owner user: ");
273 pw.print(getOwnerUserId());
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700274 pw.println();
275
Makoto Onukic51b2872016-05-04 15:24:50 -0700276 getPackageInfo().dump(pw, prefix + " ");
Makoto Onuki31459242016-03-22 11:12:18 -0700277 pw.println();
278
279 final int size = mPinnedShortcuts.size();
280 for (int i = 0; i < size; i++) {
281 pw.println();
282
Makoto Onuki2e210c42016-03-30 08:30:36 -0700283 final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
284
Makoto Onuki31459242016-03-22 11:12:18 -0700285 pw.print(prefix);
286 pw.print(" ");
287 pw.print("Package: ");
Makoto Onuki2e210c42016-03-30 08:30:36 -0700288 pw.print(pu.packageName);
289 pw.print(" User: ");
290 pw.println(pu.userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700291
292 final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
293 final int idSize = ids.size();
294
295 for (int j = 0; j < idSize; j++) {
296 pw.print(prefix);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700297 pw.print(" Pinned: ");
Makoto Onuki31459242016-03-22 11:12:18 -0700298 pw.print(ids.valueAt(j));
299 pw.println();
300 }
301 }
302 }
Makoto Onuki2e210c42016-03-30 08:30:36 -0700303
Makoto Onuki76269922016-07-15 14:58:54 -0700304 @Override
305 public JSONObject dumpCheckin(boolean clear) throws JSONException {
306 final JSONObject result = super.dumpCheckin(clear);
307
308 // Nothing really interesting to dump.
309
310 return result;
311 }
312
Makoto Onuki2e210c42016-03-30 08:30:36 -0700313 @VisibleForTesting
314 ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
315 return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
316 }
Makoto Onuki31459242016-03-22 11:12:18 -0700317}