blob: 5d4bfa4dcb3e55f027ba724ca84bfb9162c88ae1 [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;
Makoto Onukic51b2872016-05-04 15:24:50 -070019import android.annotation.Nullable;
Makoto Onuki31459242016-03-22 11:12:18 -070020import android.annotation.UserIdInt;
21import android.content.ComponentName;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070022import android.content.pm.ShortcutManager;
23import android.text.TextUtils;
Makoto Onuki0033b2a2016-04-14 17:19:16 -070024import android.text.format.Formatter;
Makoto Onuki31459242016-03-22 11:12:18 -070025import android.util.ArrayMap;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -070026import android.util.Log;
Makoto Onuki0acbb142016-03-22 17:02:57 -070027import android.util.Slog;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070028import android.util.SparseArray;
Makoto Onuki31459242016-03-22 11:12:18 -070029
Makoto Onuki22fcc682016-05-17 14:52:19 -070030import com.android.internal.annotations.GuardedBy;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070031import com.android.internal.annotations.VisibleForTesting;
Makoto Onukid99c6f02016-03-28 11:02:54 -070032import com.android.internal.util.Preconditions;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -070033import com.android.server.pm.ShortcutService.InvalidFileFormatException;
Makoto Onukid99c6f02016-03-28 11:02:54 -070034
Makoto Onuki31459242016-03-22 11:12:18 -070035import libcore.util.Objects;
36
Makoto Onuki76269922016-07-15 14:58:54 -070037import org.json.JSONArray;
38import org.json.JSONException;
39import org.json.JSONObject;
Makoto Onuki31459242016-03-22 11:12:18 -070040import org.xmlpull.v1.XmlPullParser;
41import org.xmlpull.v1.XmlPullParserException;
42import org.xmlpull.v1.XmlSerializer;
43
Makoto Onuki0033b2a2016-04-14 17:19:16 -070044import java.io.File;
Makoto Onuki31459242016-03-22 11:12:18 -070045import java.io.IOException;
46import java.io.PrintWriter;
Makoto Onuki9da23fc2016-03-29 11:14:42 -070047import java.util.function.Consumer;
Makoto Onuki31459242016-03-22 11:12:18 -070048
49/**
50 * User information used by {@link ShortcutService}.
Makoto Onuki22fcc682016-05-17 14:52:19 -070051 *
52 * All methods should be guarded by {@code #mService.mLock}.
Makoto Onuki31459242016-03-22 11:12:18 -070053 */
54class ShortcutUser {
55 private static final String TAG = ShortcutService.TAG;
56
57 static final String TAG_ROOT = "user";
58 private static final String TAG_LAUNCHER = "launcher";
59
60 private static final String ATTR_VALUE = "value";
Makoto Onuki4e6cef42016-07-13 16:14:01 -070061 private static final String ATTR_KNOWN_LOCALES = "locales";
Makoto Onuki4dd032d2016-08-02 11:39:19 -070062
63 // Suffix "2" was added to force rescan all packages after the next OTA.
64 private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
Makoto Onuki33663282016-08-22 16:19:04 -070065 private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
Makoto Onuki76269922016-07-15 14:58:54 -070066 private static final String KEY_USER_ID = "userId";
67 private static final String KEY_LAUNCHERS = "launchers";
68 private static final String KEY_PACKAGES = "packages";
Makoto Onuki31459242016-03-22 11:12:18 -070069
Makoto Onukid99c6f02016-03-28 11:02:54 -070070 static final class PackageWithUser {
71 final int userId;
72 final String packageName;
73
74 private PackageWithUser(int userId, String packageName) {
75 this.userId = userId;
76 this.packageName = Preconditions.checkNotNull(packageName);
77 }
78
Makoto Onuki2e210c42016-03-30 08:30:36 -070079 public static PackageWithUser of(int userId, String packageName) {
80 return new PackageWithUser(userId, packageName);
Makoto Onukid99c6f02016-03-28 11:02:54 -070081 }
82
Makoto Onuki9da23fc2016-03-29 11:14:42 -070083 public static PackageWithUser of(ShortcutPackageItem spi) {
84 return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
85 }
86
Makoto Onukid99c6f02016-03-28 11:02:54 -070087 @Override
88 public int hashCode() {
89 return packageName.hashCode() ^ userId;
90 }
91
92 @Override
93 public boolean equals(Object obj) {
94 if (!(obj instanceof PackageWithUser)) {
95 return false;
96 }
97 final PackageWithUser that = (PackageWithUser) obj;
98
99 return userId == that.userId && packageName.equals(that.packageName);
100 }
101
102 @Override
103 public String toString() {
Makoto Onukib08790c2016-06-23 14:05:46 -0700104 return String.format("[Package: %d, %s]", userId, packageName);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700105 }
106 }
107
Makoto Onukic51b2872016-05-04 15:24:50 -0700108 final ShortcutService mService;
109
Makoto Onuki31459242016-03-22 11:12:18 -0700110 @UserIdInt
Makoto Onuki2e210c42016-03-30 08:30:36 -0700111 private final int mUserId;
Makoto Onuki31459242016-03-22 11:12:18 -0700112
113 private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
114
Makoto Onukid99c6f02016-03-28 11:02:54 -0700115 private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
Makoto Onuki31459242016-03-22 11:12:18 -0700116
Makoto Onuki10305202016-07-14 18:14:08 -0700117 /**
118 * Last known launcher. It's used when the default launcher isn't set in PM -- i.e.
119 * when getHomeActivitiesAsUser() return null. We need it so that in this situation the
120 * previously default launcher can still access shortcuts.
121 */
122 private ComponentName mLastKnownLauncher;
123
124 /** In-memory-cached default launcher. */
125 private ComponentName mCachedLauncher;
Makoto Onuki31459242016-03-22 11:12:18 -0700126
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700127 private String mKnownLocales;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700128
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700129 private long mLastAppScanTime;
130
Makoto Onuki33663282016-08-22 16:19:04 -0700131 private String mLastAppScanOsFingerprint;
132
Makoto Onukic51b2872016-05-04 15:24:50 -0700133 public ShortcutUser(ShortcutService service, int userId) {
134 mService = service;
Makoto Onuki31459242016-03-22 11:12:18 -0700135 mUserId = userId;
136 }
137
Makoto Onuki2e210c42016-03-30 08:30:36 -0700138 public int getUserId() {
139 return mUserId;
140 }
141
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700142 public long getLastAppScanTime() {
143 return mLastAppScanTime;
144 }
145
146 public void setLastAppScanTime(long lastAppScanTime) {
147 mLastAppScanTime = lastAppScanTime;
148 }
149
Makoto Onuki33663282016-08-22 16:19:04 -0700150 public String getLastAppScanOsFingerprint() {
151 return mLastAppScanOsFingerprint;
152 }
153
154 public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
155 mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
156 }
157
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700158 // We don't expose this directly to non-test code because only ShortcutUser should add to/
159 // remove from it.
160 @VisibleForTesting
161 ArrayMap<String, ShortcutPackage> getAllPackagesForTest() {
Makoto Onuki31459242016-03-22 11:12:18 -0700162 return mPackages;
163 }
164
Makoto Onuki6c1dbd52016-05-02 15:19:32 -0700165 public boolean hasPackage(@NonNull String packageName) {
166 return mPackages.containsKey(packageName);
167 }
168
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700169 private void addPackage(@NonNull ShortcutPackage p) {
170 p.replaceUser(this);
171 mPackages.put(p.getPackageName(), p);
172 }
173
Makoto Onukic51b2872016-05-04 15:24:50 -0700174 public ShortcutPackage removePackage(@NonNull String packageName) {
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700175 final ShortcutPackage removed = mPackages.remove(packageName);
176
Makoto Onukic51b2872016-05-04 15:24:50 -0700177 mService.cleanupBitmapsForPackage(mUserId, packageName);
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700178
179 return removed;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700180 }
181
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700182 // We don't expose this directly to non-test code because only ShortcutUser should add to/
183 // remove from it.
184 @VisibleForTesting
185 ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchersForTest() {
Makoto Onuki31459242016-03-22 11:12:18 -0700186 return mLaunchers;
187 }
188
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700189 private void addLauncher(ShortcutLauncher launcher) {
190 launcher.replaceUser(this);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700191 mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
192 launcher.getPackageName()), launcher);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700193 }
194
Makoto Onukic51b2872016-05-04 15:24:50 -0700195 @Nullable
Makoto Onukid99c6f02016-03-28 11:02:54 -0700196 public ShortcutLauncher removeLauncher(
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700197 @UserIdInt int packageUserId, @NonNull String packageName) {
198 return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
Makoto Onukid99c6f02016-03-28 11:02:54 -0700199 }
200
Makoto Onukic51b2872016-05-04 15:24:50 -0700201 @Nullable
202 public ShortcutPackage getPackageShortcutsIfExists(@NonNull String packageName) {
203 final ShortcutPackage ret = mPackages.get(packageName);
204 if (ret != null) {
205 ret.attemptToRestoreIfNeededAndSave();
Makoto Onuki31459242016-03-22 11:12:18 -0700206 }
207 return ret;
208 }
209
Makoto Onukic51b2872016-05-04 15:24:50 -0700210 @NonNull
211 public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
212 ShortcutPackage ret = getPackageShortcutsIfExists(packageName);
213 if (ret == null) {
214 ret = new ShortcutPackage(this, mUserId, packageName);
215 mPackages.put(packageName, ret);
216 }
217 return ret;
218 }
219
220 @NonNull
221 public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
Makoto Onukid99c6f02016-03-28 11:02:54 -0700222 @UserIdInt int launcherUserId) {
223 final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
224 ShortcutLauncher ret = mLaunchers.get(key);
Makoto Onuki31459242016-03-22 11:12:18 -0700225 if (ret == null) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700226 ret = new ShortcutLauncher(this, mUserId, packageName, launcherUserId);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700227 mLaunchers.put(key, ret);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700228 } else {
Makoto Onukic51b2872016-05-04 15:24:50 -0700229 ret.attemptToRestoreIfNeededAndSave();
Makoto Onuki31459242016-03-22 11:12:18 -0700230 }
231 return ret;
232 }
233
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700234 public void forAllPackages(Consumer<? super ShortcutPackage> callback) {
235 final int size = mPackages.size();
236 for (int i = 0; i < size; i++) {
237 callback.accept(mPackages.valueAt(i));
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700238 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700239 }
240
241 public void forAllLaunchers(Consumer<? super ShortcutLauncher> callback) {
242 final int size = mLaunchers.size();
243 for (int i = 0; i < size; i++) {
244 callback.accept(mLaunchers.valueAt(i));
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700245 }
246 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700247
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700248 public void forAllPackageItems(Consumer<? super ShortcutPackageItem> callback) {
249 forAllLaunchers(callback);
250 forAllPackages(callback);
251 }
252
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700253 public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
254 Consumer<ShortcutPackageItem> callback) {
255 forAllPackageItems(spi -> {
256 if ((spi.getPackageUserId() == packageUserId)
257 && spi.getPackageName().equals(packageName)) {
258 callback.accept(spi);
259 }
260 });
Makoto Onuki0acbb142016-03-22 17:02:57 -0700261 }
262
Makoto Onuki39686e82016-04-13 18:03:00 -0700263 /**
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700264 * Must be called at any entry points on {@link ShortcutManager} APIs to make sure the
265 * information on the package is up-to-date.
266 *
267 * We use broadcasts to handle locale changes and package changes, but because broadcasts
268 * are asynchronous, there's a chance a publisher calls getXxxShortcuts() after a certain event
269 * (e.g. system locale change) but shortcut manager hasn't finished processing the broadcast.
270 *
271 * So we call this method at all entry points from publishers to make sure we update all
272 * relevant information.
273 *
274 * Similar inconsistencies can happen when the launcher fetches shortcut information, but
275 * that's a less of an issue because for the launcher we report shortcut changes with
276 * callbacks.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700277 */
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700278 public void onCalledByPublisher(@NonNull String packageName) {
279 detectLocaleChange();
280 rescanPackageIfNeeded(packageName, /*forceRescan=*/ false);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700281 }
282
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700283 private String getKnownLocales() {
284 if (TextUtils.isEmpty(mKnownLocales)) {
285 mKnownLocales = mService.injectGetLocaleTagsForUser(mUserId);
286 mService.scheduleSaveUser(mUserId);
287 }
288 return mKnownLocales;
289 }
290
291 /**
292 * Check to see if the system locale has changed, and if so, reset throttling
293 * and update resource strings.
294 */
295 public void detectLocaleChange() {
296 final String currentLocales = mService.injectGetLocaleTagsForUser(mUserId);
297 if (getKnownLocales().equals(currentLocales)) {
298 return;
299 }
300 if (ShortcutService.DEBUG) {
301 Slog.d(TAG, "Locale changed from " + currentLocales + " to " + mKnownLocales
302 + " for user " + mUserId);
303 }
304 mKnownLocales = currentLocales;
305
306 forAllPackages(pkg -> {
307 pkg.resetRateLimiting();
308 pkg.resolveResourceStrings();
309 });
310
311 mService.scheduleSaveUser(mUserId);
312 }
313
314 public void rescanPackageIfNeeded(@NonNull String packageName, boolean forceRescan) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700315 final boolean isNewApp = !mPackages.containsKey(packageName);
316
317 final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
318
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700319 if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700320 if (isNewApp) {
321 mPackages.remove(packageName);
322 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700323 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700324 }
325
Makoto Onuki2e210c42016-03-30 08:30:36 -0700326 public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
327 @UserIdInt int packageUserId) {
328 forPackageItem(packageName, packageUserId, spi -> {
Makoto Onukic51b2872016-05-04 15:24:50 -0700329 spi.attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -0700330 });
331 }
332
Makoto Onukic51b2872016-05-04 15:24:50 -0700333 public void saveToXml(XmlSerializer out, boolean forBackup)
Makoto Onuki0acbb142016-03-22 17:02:57 -0700334 throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700335 out.startTag(null, TAG_ROOT);
336
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700337 if (!forBackup) {
338 // Don't have to back them up.
339 ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
340 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
341 mLastAppScanTime);
342 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
343 mLastAppScanOsFingerprint);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700344
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700345 ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
346 }
Makoto Onuki31459242016-03-22 11:12:18 -0700347
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700348 // Can't use forEachPackageItem due to the checked exceptions.
Makoto Onuki0acbb142016-03-22 17:02:57 -0700349 {
350 final int size = mLaunchers.size();
351 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700352 saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700353 }
354 }
355 {
356 final int size = mPackages.size();
357 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700358 saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700359 }
Makoto Onuki31459242016-03-22 11:12:18 -0700360 }
361
362 out.endTag(null, TAG_ROOT);
363 }
364
Makoto Onukic51b2872016-05-04 15:24:50 -0700365 private void saveShortcutPackageItem(XmlSerializer out,
Makoto Onuki0acbb142016-03-22 17:02:57 -0700366 ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700367 if (forBackup) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700368 if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700369 return; // Don't save.
370 }
371 if (spi.getPackageUserId() != spi.getOwnerUserId()) {
372 return; // Don't save cross-user information.
373 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700374 }
375 spi.saveToXml(out, forBackup);
376 }
377
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700378 public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700379 boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
Makoto Onukic51b2872016-05-04 15:24:50 -0700380 final ShortcutUser ret = new ShortcutUser(s, userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700381
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700382 try {
383 ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
384 ATTR_KNOWN_LOCALES);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700385
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700386 // If lastAppScanTime is in the future, that means the clock went backwards.
387 // Just scan all apps again.
388 final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
389 ATTR_LAST_APP_SCAN_TIME);
390 final long currentTime = s.injectCurrentTimeMillis();
391 ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
392 ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
393 ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
394 final int outerDepth = parser.getDepth();
395 int type;
396 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
397 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
398 if (type != XmlPullParser.START_TAG) {
399 continue;
400 }
401 final int depth = parser.getDepth();
402 final String tag = parser.getName();
Makoto Onuki31459242016-03-22 11:12:18 -0700403
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700404 if (depth == outerDepth + 1) {
405 switch (tag) {
406 case TAG_LAUNCHER: {
407 ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
408 parser, ATTR_VALUE);
409 continue;
410 }
411 case ShortcutPackage.TAG_ROOT: {
412 final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
413 s, ret, parser, fromBackup);
Makoto Onuki31459242016-03-22 11:12:18 -0700414
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700415 // Don't use addShortcut(), we don't need to save the icon.
416 ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
417 continue;
418 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700419
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700420 case ShortcutLauncher.TAG_ROOT: {
421 ret.addLauncher(
422 ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
423 continue;
424 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700425 }
Makoto Onuki31459242016-03-22 11:12:18 -0700426 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700427 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki31459242016-03-22 11:12:18 -0700428 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700429 } catch (RuntimeException e) {
430 throw new ShortcutService.InvalidFileFormatException(
431 "Unable to parse file", e);
Makoto Onuki31459242016-03-22 11:12:18 -0700432 }
433 return ret;
434 }
435
Makoto Onuki10305202016-07-14 18:14:08 -0700436 public ComponentName getLastKnownLauncher() {
437 return mLastKnownLauncher;
Makoto Onuki31459242016-03-22 11:12:18 -0700438 }
439
Makoto Onuki10305202016-07-14 18:14:08 -0700440 public void setLauncher(ComponentName launcherComponent) {
441 setLauncher(launcherComponent, /* allowPurgeLastKnown */ false);
442 }
443
444 /** Clears the launcher information without clearing the last known one */
445 public void clearLauncher() {
446 setLauncher(null);
447 }
448
449 /**
450 * Clears the launcher information *with(* clearing the last known one; we do this witl
451 * "cmd shortcut clear-default-launcher".
452 */
453 public void forceClearLauncher() {
454 setLauncher(null, /* allowPurgeLastKnown */ true);
455 }
456
457 private void setLauncher(ComponentName launcherComponent, boolean allowPurgeLastKnown) {
458 mCachedLauncher = launcherComponent; // Always update the in-memory cache.
459
460 if (Objects.equal(mLastKnownLauncher, launcherComponent)) {
Makoto Onuki31459242016-03-22 11:12:18 -0700461 return;
462 }
Makoto Onuki10305202016-07-14 18:14:08 -0700463 if (!allowPurgeLastKnown && launcherComponent == null) {
464 return;
465 }
466 mLastKnownLauncher = launcherComponent;
Makoto Onukic51b2872016-05-04 15:24:50 -0700467 mService.scheduleSaveUser(mUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700468 }
469
Makoto Onuki10305202016-07-14 18:14:08 -0700470 public ComponentName getCachedLauncher() {
471 return mCachedLauncher;
472 }
473
Makoto Onuki31459242016-03-22 11:12:18 -0700474 public void resetThrottling() {
475 for (int i = mPackages.size() - 1; i >= 0; i--) {
476 mPackages.valueAt(i).resetThrottling();
477 }
478 }
479
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700480 public void mergeRestoredFile(ShortcutUser restored) {
481 final ShortcutService s = mService;
482 // Note, a restore happens only at the end of setup wizard. At this point, no apps are
483 // installed from Play Store yet, but it's still possible that system apps have already
484 // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
485 // When such a system app has allowbackup=true, then we go ahead and replace all existing
486 // shortcuts with the restored shortcuts. (Then we'll re-publish manifest shortcuts later
487 // in the call site.)
488 // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
489 // already been published. So we selectively add restored ShortcutPackages here.
490 //
491 // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
492 // without users interaction it's really not a big deal, so we just clear existing
493 // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
494
495 mLaunchers.clear();
496 restored.forAllLaunchers(sl -> {
497 // If the app is already installed and allowbackup = false, then ignore the restored
498 // data.
499 if (s.isPackageInstalled(sl.getPackageName(), getUserId())
500 && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
501 return;
502 }
503 addLauncher(sl);
504 });
505 restored.forAllPackages(sp -> {
506 // If the app is already installed and allowbackup = false, then ignore the restored
507 // data.
508 if (s.isPackageInstalled(sp.getPackageName(), getUserId())
509 && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
510 return;
511 }
512
513 final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
514 if (previous != null && previous.hasNonManifestShortcuts()) {
515 Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
516 + " Existing non-manifeset shortcuts will be overwritten.");
517 }
518 addPackage(sp);
519 });
520 // Empty the launchers and packages in restored to avoid accidentally using them.
521 restored.mLaunchers.clear();
522 restored.mPackages.clear();
523 }
524
Makoto Onukic51b2872016-05-04 15:24:50 -0700525 public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
Makoto Onuki31459242016-03-22 11:12:18 -0700526 pw.print(prefix);
527 pw.print("User: ");
528 pw.print(mUserId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700529 pw.print(" Known locales: ");
530 pw.print(mKnownLocales);
Makoto Onukib08790c2016-06-23 14:05:46 -0700531 pw.print(" Last app scan: [");
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700532 pw.print(mLastAppScanTime);
Makoto Onukib08790c2016-06-23 14:05:46 -0700533 pw.print("] ");
534 pw.print(ShortcutService.formatTime(mLastAppScanTime));
Makoto Onuki33663282016-08-22 16:19:04 -0700535 pw.print(" Last app scan FP: ");
536 pw.print(mLastAppScanOsFingerprint);
Makoto Onuki31459242016-03-22 11:12:18 -0700537 pw.println();
538
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700539 prefix += prefix + " ";
540
Makoto Onuki31459242016-03-22 11:12:18 -0700541 pw.print(prefix);
Makoto Onuki10305202016-07-14 18:14:08 -0700542 pw.print("Cached launcher: ");
543 pw.print(mCachedLauncher);
544 pw.println();
545
546 pw.print(prefix);
547 pw.print("Last known launcher: ");
548 pw.print(mLastKnownLauncher);
Makoto Onuki31459242016-03-22 11:12:18 -0700549 pw.println();
550
551 for (int i = 0; i < mLaunchers.size(); i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700552 mLaunchers.valueAt(i).dump(pw, prefix);
Makoto Onuki31459242016-03-22 11:12:18 -0700553 }
554
555 for (int i = 0; i < mPackages.size(); i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700556 mPackages.valueAt(i).dump(pw, prefix);
Makoto Onuki31459242016-03-22 11:12:18 -0700557 }
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700558
559 pw.println();
560 pw.print(prefix);
561 pw.println("Bitmap directories: ");
Makoto Onukic51b2872016-05-04 15:24:50 -0700562 dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId));
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700563 }
564
Makoto Onukic51b2872016-05-04 15:24:50 -0700565 private void dumpDirectorySize(@NonNull PrintWriter pw,
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700566 @NonNull String prefix, File path) {
567 int numFiles = 0;
568 long size = 0;
569 final File[] children = path.listFiles();
570 if (children != null) {
571 for (File child : path.listFiles()) {
572 if (child.isFile()) {
573 numFiles++;
574 size += child.length();
575 } else if (child.isDirectory()) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700576 dumpDirectorySize(pw, prefix + " ", child);
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700577 }
578 }
579 }
580 pw.print(prefix);
581 pw.print("Path: ");
582 pw.print(path.getName());
583 pw.print("/ has ");
584 pw.print(numFiles);
585 pw.print(" files, size=");
586 pw.print(size);
587 pw.print(" (");
Makoto Onukic51b2872016-05-04 15:24:50 -0700588 pw.print(Formatter.formatFileSize(mService.mContext, size));
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700589 pw.println(")");
Makoto Onuki31459242016-03-22 11:12:18 -0700590 }
Makoto Onuki76269922016-07-15 14:58:54 -0700591
592 public JSONObject dumpCheckin(boolean clear) throws JSONException {
593 final JSONObject result = new JSONObject();
594
595 result.put(KEY_USER_ID, mUserId);
596
597 {
598 final JSONArray launchers = new JSONArray();
599 for (int i = 0; i < mLaunchers.size(); i++) {
600 launchers.put(mLaunchers.valueAt(i).dumpCheckin(clear));
601 }
602 result.put(KEY_LAUNCHERS, launchers);
603 }
604
605 {
606 final JSONArray packages = new JSONArray();
607 for (int i = 0; i < mPackages.size(); i++) {
608 packages.put(mPackages.valueAt(i).dumpCheckin(clear));
609 }
610 result.put(KEY_PACKAGES, packages);
611 }
612
613 return result;
614 }
Makoto Onuki31459242016-03-22 11:12:18 -0700615}