blob: 04a7ecd826a9d81105bad47fef6f236e5f802733 [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 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 */
16
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Sunny Goyala7a5bf32020-01-05 15:35:29 +053019import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
20import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
21import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
22import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
23import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
24
Sunny Goyal14168432019-10-24 15:59:49 -070025import android.content.Context;
Sunny Goyalf599ccf2014-07-08 13:01:29 -070026import android.content.Intent;
Sunny Goyale7b00122019-10-02 16:13:34 -070027import android.content.pm.LauncherApps;
Sunny Goyal045b4fa2019-09-20 12:51:37 -070028import android.content.pm.PackageInstaller;
Sunny Goyal6bbf6002019-04-17 18:38:52 -070029import android.content.pm.ShortcutInfo;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -080030import android.os.UserHandle;
Winson Chunga90303b2013-11-15 13:05:06 -080031import android.text.TextUtils;
Winson Chungaafa03c2010-06-11 17:34:16 -070032import android.util.Log;
Sunny Goyala474a9b2017-05-04 16:47:11 -070033import android.util.Pair;
Michael Jurka34c2e6c2013-12-13 16:07:45 +010034
Sunny Goyal6fe3eec2019-08-15 14:53:41 -070035import androidx.annotation.Nullable;
Sunny Goyal14168432019-10-24 15:59:49 -070036import androidx.annotation.WorkerThread;
Sunny Goyal6fe3eec2019-08-15 14:53:41 -070037
Sunny Goyal045b4fa2019-09-20 12:51:37 -070038import com.android.launcher3.config.FeatureFlags;
Sunny Goyalf840f102018-09-21 14:41:05 -070039import com.android.launcher3.icons.IconCache;
Sunny Goyalc5939392018-12-07 11:43:47 -080040import com.android.launcher3.icons.LauncherIcons;
Samuel Fufacc1e1072019-09-06 16:19:11 -070041import com.android.launcher3.logging.FileLog;
Sunny Goyalf0ba8b72016-09-09 15:47:55 -070042import com.android.launcher3.model.AddWorkspaceItemsTask;
Sunny Goyal87dcde62019-07-17 20:35:56 -070043import com.android.launcher3.model.AllAppsList;
Sunny Goyale75d9f12018-01-31 11:59:00 -080044import com.android.launcher3.model.BaseModelUpdateTask;
Sunny Goyale9956a72016-09-01 17:24:47 -070045import com.android.launcher3.model.BgDataModel;
Sunny Goyal87dcde62019-07-17 20:35:56 -070046import com.android.launcher3.model.BgDataModel.Callbacks;
Sunny Goyalf0ba8b72016-09-09 15:47:55 -070047import com.android.launcher3.model.CacheDataUpdatedTask;
Sunny Goyalf8d6ed22017-06-01 14:26:38 -070048import com.android.launcher3.model.LoaderResults;
Sunny Goyalb434fde2017-06-06 10:46:59 -070049import com.android.launcher3.model.LoaderTask;
Sunny Goyal43bf11d2017-02-02 13:52:53 -080050import com.android.launcher3.model.ModelWriter;
Sunny Goyalf0ba8b72016-09-09 15:47:55 -070051import com.android.launcher3.model.PackageInstallStateChangedTask;
52import com.android.launcher3.model.PackageUpdatedTask;
53import com.android.launcher3.model.ShortcutsChangedTask;
54import com.android.launcher3.model.UserLockStateChangedTask;
Sunny Goyal045b4fa2019-09-20 12:51:37 -070055import com.android.launcher3.pm.InstallSessionTracker;
56import com.android.launcher3.pm.PackageInstallInfo;
Sunny Goyal337c81f2019-12-10 12:19:13 -080057import com.android.launcher3.pm.UserCache;
Sunny Goyalfa395362019-12-11 10:00:47 -080058import com.android.launcher3.shortcuts.ShortcutRequest;
vadimtc8b09702020-01-27 17:44:44 -080059import com.android.launcher3.testing.TestProtocol;
Jon Miranda088b9c22019-09-17 11:51:49 -070060import com.android.launcher3.util.IntSparseArrayMap;
61import com.android.launcher3.util.ItemInfoMatcher;
Sunny Goyala7a5bf32020-01-05 15:35:29 +053062import com.android.launcher3.util.LooperExecutor;
Tony Wickham86222d22017-03-29 15:30:43 -070063import com.android.launcher3.util.PackageUserKey;
Sunny Goyalaaf7d1d2016-05-17 13:38:54 -070064import com.android.launcher3.util.Preconditions;
Romain Guyedcce092010-03-04 13:03:17 -080065
Hyunyoung Song3c7d9cb2017-01-30 15:11:27 -080066import java.io.FileDescriptor;
67import java.io.PrintWriter;
Michael Jurkac2f801e2011-07-12 14:19:46 -070068import java.util.ArrayList;
Winson Chungb8b2a5a2012-07-12 17:55:31 -070069import java.util.HashSet;
Michael Jurkac2f801e2011-07-12 14:19:46 -070070import java.util.List;
Hyunyoung Song97253ec2019-12-25 13:51:28 -080071import java.util.Optional;
Sunny Goyaldd96a5e2017-02-17 11:22:34 -080072import java.util.concurrent.CancellationException;
Sunny Goyal527c7d32015-08-28 15:19:36 -070073import java.util.concurrent.Executor;
Sunny Goyal8c48d8b2019-01-25 15:10:18 -080074import java.util.function.Supplier;
Michael Jurkac2f801e2011-07-12 14:19:46 -070075
The Android Open Source Project31dd5032009-03-03 19:32:27 -080076/**
77 * Maintains in-memory state of the Launcher. It is expected that there should be only one
78 * LauncherModel object held in a static. Also provide APIs for updating the database state
The Android Open Source Projectbc219c32009-03-09 11:52:14 -070079 * for the Launcher.
The Android Open Source Project31dd5032009-03-03 19:32:27 -080080 */
Sunny Goyale7b00122019-10-02 16:13:34 -070081public class LauncherModel extends LauncherApps.Callback implements InstallSessionTracker.Callback {
Chris Wrenee523362014-09-09 10:09:02 -040082 private static final boolean DEBUG_RECEIVER = false;
Chris Wrenb358f812014-04-16 13:37:00 -040083
Joe Onorato9c1289c2009-08-17 11:03:03 -040084 static final String TAG = "Launcher.Model";
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070085
Sunny Goyala7a5bf32020-01-05 15:35:29 +053086 private final LauncherAppState mApp;
87 private final Object mLock = new Object();
88 private final LooperExecutor mMainExecutor = MAIN_EXECUTOR;
89
90 private LoaderTask mLoaderTask;
91 private boolean mIsLoaderTaskRunning;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080092
Sunny Goyaldd96a5e2017-02-17 11:22:34 -080093 // Indicates whether the current model data is valid or not.
94 // We start off with everything not loaded. After that, we assume that
Joe Onoratocc67f472010-06-08 10:54:30 -070095 // our monitoring of the package manager provides all updates and we never
Sunny Goyaldd96a5e2017-02-17 11:22:34 -080096 // need to do a requery. This is only ever touched from the loader thread.
97 private boolean mModelLoaded;
Hyunyoung Song6aa37292017-02-06 10:46:24 -080098 public boolean isModelLoaded() {
99 synchronized (mLock) {
vadimtc8b09702020-01-27 17:44:44 -0800100 if (TestProtocol.sDebugTracing) {
101 Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
102 "isModelLoaded: " + mModelLoaded + ", " + mLoaderTask);
103 }
Hyunyoung Song6aa37292017-02-06 10:46:24 -0800104 return mModelLoaded && mLoaderTask == null;
105 }
106 }
Joe Onoratocc67f472010-06-08 10:54:30 -0700107
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530108 private final ArrayList<Callbacks> mCallbacksList = new ArrayList<>(1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800109
Michael Jurkaa8c760d2011-04-28 14:59:33 -0700110 // < only access in worker thread >
Sunny Goyal2e1efb42016-03-03 16:58:55 -0800111 private final AllAppsList mBgAllAppsList;
Sunny Goyal95f3d6b2016-08-10 16:09:29 -0700112
Sunny Goyale9956a72016-09-01 17:24:47 -0700113 /**
114 * All the static data should be accessed on the background thread, A lock should be acquired
115 * on this object when accessing any data from this model.
116 */
Sunny Goyal9ae9b602019-12-18 19:29:00 +0530117 private final BgDataModel mBgDataModel = new BgDataModel();
Tony Wickhambfbf7f92016-05-19 11:19:39 -0700118
Sunny Goyalc6e97692017-06-02 13:46:55 -0700119 // Runnable to check if the shortcuts permission has changed.
120 private final Runnable mShortcutPermissionCheckRunnable = new Runnable() {
121 @Override
122 public void run() {
Sunny Goyalfa395362019-12-11 10:00:47 -0800123 if (mModelLoaded && hasShortcutsPermission(mApp.getContext())
Sunny Goyal9ae9b602019-12-18 19:29:00 +0530124 != mBgDataModel.hasShortcutHostPermission) {
Sunny Goyalfa395362019-12-11 10:00:47 -0800125 forceReload();
Sunny Goyalc6e97692017-06-02 13:46:55 -0700126 }
127 }
128 };
Kenny Guyed131872014-04-30 03:02:21 +0100129
Sunny Goyaldde4fd92016-11-21 16:02:39 +0530130 LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
Daniel Sandlere4f98912013-06-25 15:13:26 -0400131 mApp = app;
Bjorn Bringert1307f632013-10-03 22:31:03 +0100132 mBgAllAppsList = new AllAppsList(iconCache, appFilter);
Joe Onorato0589f0f2010-02-08 13:44:00 -0800133 }
134
Sunny Goyal71b5c0b2015-01-08 16:59:04 -0800135 /**
Hyunyoung Song97253ec2019-12-25 13:51:28 -0800136 * Returns AppInfo with corresponding package name.
137 * TODO: move to enqueueModelTask
138 */
139 public Optional<AppInfo> getAppInfoByPackageName(String pkg) {
140 return mBgAllAppsList.data.stream()
141 .filter(info -> info.componentName.getPackageName().equals(pkg))
142 .findAny();
143 }
144
145 /**
Sunny Goyal71b5c0b2015-01-08 16:59:04 -0800146 * Adds the provided items to the workspace.
Sunny Goyal71b5c0b2015-01-08 16:59:04 -0800147 */
Sunny Goyal91498ab2017-10-05 15:57:40 -0700148 public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) {
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530149 for (Callbacks cb : getCallbacks()) {
150 cb.preAddApps();
Tony Wickham6a71a5b2018-08-21 11:40:23 -0700151 }
Sunny Goyal91498ab2017-10-05 15:57:40 -0700152 enqueueModelUpdateTask(new AddWorkspaceItemsTask(itemList));
Winson Chung64359a52013-07-08 17:17:08 -0700153 }
154
Sunny Goyal605bcf32018-03-02 15:16:12 -0800155 public ModelWriter getWriter(boolean hasVerticalHotseat, boolean verifyChanges) {
Sunny Goyal9ae9b602019-12-18 19:29:00 +0530156 return new ModelWriter(mApp.getContext(), this, mBgDataModel,
Sunny Goyal605bcf32018-03-02 15:16:12 -0800157 hasVerticalHotseat, verifyChanges);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800158 }
159
Kenny Guyed131872014-04-30 03:02:21 +0100160 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800161 public void onPackageChanged(String packageName, UserHandle user) {
Kenny Guyed131872014-04-30 03:02:21 +0100162 int op = PackageUpdatedTask.OP_UPDATE;
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700163 enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
Kenny Guyed131872014-04-30 03:02:21 +0100164 }
165
166 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800167 public void onPackageRemoved(String packageName, UserHandle user) {
Sunny Goyalc2936bc2016-09-01 15:50:36 -0700168 onPackagesRemoved(user, packageName);
169 }
170
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800171 public void onPackagesRemoved(UserHandle user, String... packages) {
Kenny Guyed131872014-04-30 03:02:21 +0100172 int op = PackageUpdatedTask.OP_REMOVE;
Samuel Fufacc1e1072019-09-06 16:19:11 -0700173 FileLog.d(TAG, "package removed received " + String.join("," + packages));
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700174 enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packages));
Kenny Guyed131872014-04-30 03:02:21 +0100175 }
176
177 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800178 public void onPackageAdded(String packageName, UserHandle user) {
Kenny Guyed131872014-04-30 03:02:21 +0100179 int op = PackageUpdatedTask.OP_ADD;
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700180 enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
Kenny Guyed131872014-04-30 03:02:21 +0100181 }
182
183 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800184 public void onPackagesAvailable(String[] packageNames, UserHandle user,
Kenny Guyed131872014-04-30 03:02:21 +0100185 boolean replacing) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700186 enqueueModelUpdateTask(
187 new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, user, packageNames));
Kenny Guyed131872014-04-30 03:02:21 +0100188 }
189
190 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800191 public void onPackagesUnavailable(String[] packageNames, UserHandle user,
Kenny Guyed131872014-04-30 03:02:21 +0100192 boolean replacing) {
193 if (!replacing) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700194 enqueueModelUpdateTask(new PackageUpdatedTask(
195 PackageUpdatedTask.OP_UNAVAILABLE, user, packageNames));
Kenny Guyed131872014-04-30 03:02:21 +0100196 }
Kenny Guyed131872014-04-30 03:02:21 +0100197 }
198
Kenny Guy44cba692016-01-21 19:50:02 +0000199 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800200 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700201 enqueueModelUpdateTask(new PackageUpdatedTask(
202 PackageUpdatedTask.OP_SUSPEND, user, packageNames));
Kenny Guy44cba692016-01-21 19:50:02 +0000203 }
204
205 @Override
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800206 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700207 enqueueModelUpdateTask(new PackageUpdatedTask(
208 PackageUpdatedTask.OP_UNSUSPEND, user, packageNames));
Kenny Guy44cba692016-01-21 19:50:02 +0000209 }
210
Tony Wickhambfbf7f92016-05-19 11:19:39 -0700211 @Override
Sunny Goyal6bbf6002019-04-17 18:38:52 -0700212 public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800213 UserHandle user) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700214 enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, true));
Sunny Goyal50941fb2016-08-04 12:03:52 -0700215 }
216
Sunny Goyal14168432019-10-24 15:59:49 -0700217 /**
218 * Called when the icon for an app changes, outside of package event
219 */
220 @WorkerThread
221 public void onAppIconChanged(String packageName, UserHandle user) {
222 // Update the icon for the calendar package
223 Context context = mApp.getContext();
224 onPackageChanged(packageName, user);
225
Sunny Goyalfa395362019-12-11 10:00:47 -0800226 List<ShortcutInfo> pinnedShortcuts = new ShortcutRequest(context, user)
227 .forPackage(packageName).query(ShortcutRequest.PINNED);
Sunny Goyal14168432019-10-24 15:59:49 -0700228 if (!pinnedShortcuts.isEmpty()) {
229 enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, pinnedShortcuts, user,
230 false));
231 }
Tony Wickhambfbf7f92016-05-19 11:19:39 -0700232 }
233
Sunny Goyale7b00122019-10-02 16:13:34 -0700234 public void onBroadcastIntent(Intent intent) {
Chris Wrenb358f812014-04-16 13:37:00 -0400235 if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);
Joe Onorato36115782010-06-17 13:28:48 -0400236 final String action = intent.getAction();
Kenny Guyed131872014-04-30 03:02:21 +0100237 if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Reena Lee93f824a2011-09-23 17:20:28 -0700238 // If we have changed locale we need to clear out the labels in all apps/workspace.
239 forceReload();
Sunny Goyald3b87ef2016-07-28 12:11:54 -0700240 } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
241 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) ||
242 Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800243 UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
Sunny Goyalda891c12016-03-18 18:29:24 -0700244 if (user != null) {
Sunny Goyald3b87ef2016-07-28 12:11:54 -0700245 if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
246 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700247 enqueueModelUpdateTask(new PackageUpdatedTask(
248 PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE, user));
Sunny Goyald3b87ef2016-07-28 12:11:54 -0700249 }
250
251 // ACTION_MANAGED_PROFILE_UNAVAILABLE sends the profile back to locked mode, so
252 // we need to run the state change task again.
253 if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) ||
254 Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700255 enqueueModelUpdateTask(new UserLockStateChangedTask(user));
Sunny Goyald3b87ef2016-07-28 12:11:54 -0700256 }
Sunny Goyalda891c12016-03-18 18:29:24 -0700257 }
Sunny Goyal29947f02017-12-18 13:49:44 -0800258 } else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530259 for (Callbacks cb : getCallbacks()) {
260 if (cb instanceof Launcher) {
261 ((Launcher) cb).recreate();
262 }
263 }
Joe Onoratoe9ad59e2010-10-29 17:35:36 -0700264 }
265 }
266
Sunny Goyaldd96a5e2017-02-17 11:22:34 -0800267 /**
268 * Reloads the workspace items from the DB and re-binds the workspace. This should generally
269 * not be called as DB updates are automatically followed by UI update
270 */
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530271 public void forceReload() {
Sunny Goyaldd96a5e2017-02-17 11:22:34 -0800272 synchronized (mLock) {
273 // Stop any existing loaders first, so they don't set mModelLoaded to true later
Sunny Goyale86f11f2017-06-06 14:33:18 -0700274 stopLoader();
Sunny Goyaldd96a5e2017-02-17 11:22:34 -0800275 mModelLoaded = false;
276 }
Winson Chungf0c6ae02012-03-21 16:10:31 -0700277
Sunny Goyal29947f02017-12-18 13:49:44 -0800278 // Start the loader if launcher is already running, otherwise the loader will run,
279 // the next time launcher starts
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530280 if (hasCallbacks()) {
281 startLoader();
Joe Onoratoe9ad59e2010-10-29 17:35:36 -0700282 }
Joe Onorato36115782010-06-17 13:28:48 -0400283 }
Joe Onoratof99f8c12009-10-31 17:27:36 -0400284
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530285 /**
286 * Rebinds all existing callbacks with already loaded model
287 */
288 public void rebindCallbacks() {
289 if (hasCallbacks()) {
290 startLoader();
291 }
292 }
293
294 /**
295 * Removes an existing callback
296 */
297 public void removeCallbacks(Callbacks callbacks) {
298 synchronized (mCallbacksList) {
299 Preconditions.assertUIThread();
300 if (mCallbacksList.remove(callbacks)) {
301 if (stopLoader()) {
302 // Rebind existing callbacks
303 startLoader();
304 }
305 }
306 }
307 }
308
309 /**
310 * Adds a callbacks to receive model updates
311 * @return true if workspace load was performed synchronously
312 */
313 public boolean addCallbacksAndLoad(Callbacks callbacks) {
314 synchronized (mLock) {
315 addCallbacks(callbacks);
316 return startLoader();
317
318 }
319 }
320
321 /**
322 * Adds a callbacks to receive model updates
323 */
324 public void addCallbacks(Callbacks callbacks) {
325 Preconditions.assertUIThread();
326 synchronized (mCallbacksList) {
327 mCallbacksList.add(callbacks);
328 }
Adam Cohen1a85c582014-09-30 09:48:49 -0700329 }
330
Sunny Goyalb5b9ad62016-04-02 11:23:39 -0700331 /**
332 * Starts the loader. Tries to bind {@params synchronousBindPage} synchronously if possible.
333 * @return true if the page could be bound synchronously.
334 */
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530335 public boolean startLoader() {
Sunny Goyal756adbc2015-04-16 15:20:51 -0700336 // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
Sunny Goyala474a9b2017-05-04 16:47:11 -0700337 InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
Joe Onorato36115782010-06-17 13:28:48 -0400338 synchronized (mLock) {
Joe Onorato36115782010-06-17 13:28:48 -0400339 // Don't bother to start the thread if we know it's not going to do anything
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530340 final Callbacks[] callbacksList = getCallbacks();
341 if (callbacksList.length > 0) {
Sunny Goyal527c7d32015-08-28 15:19:36 -0700342 // Clear any pending bind-runnables from the synchronized load process.
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530343 for (Callbacks cb : callbacksList) {
344 mMainExecutor.execute(cb::clearPendingBinds);
345 }
Sunny Goyal527c7d32015-08-28 15:19:36 -0700346
Joe Onorato36115782010-06-17 13:28:48 -0400347 // If there is already one running, tell it to stop.
Sunny Goyale86f11f2017-06-06 14:33:18 -0700348 stopLoader();
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530349 LoaderResults loaderResults = new LoaderResults(
350 mApp, mBgDataModel, mBgAllAppsList, callbacksList, mMainExecutor);
Sunny Goyale86f11f2017-06-06 14:33:18 -0700351 if (mModelLoaded && !mIsLoaderTaskRunning) {
Sunny Goyalf8d6ed22017-06-01 14:26:38 -0700352 // Divide the set of loaded items into those that we are binding synchronously,
353 // and everything else that is to be bound normally (asynchronously).
354 loaderResults.bindWorkspace();
355 // For now, continue posting the binding of AllApps as there are other
356 // issues that arise from that.
357 loaderResults.bindAllApps();
358 loaderResults.bindDeepShortcuts();
Sunny Goyalc6e97692017-06-02 13:46:55 -0700359 loaderResults.bindWidgets();
Sunny Goyalb5b9ad62016-04-02 11:23:39 -0700360 return true;
Winson Chungb8b2a5a2012-07-12 17:55:31 -0700361 } else {
Sunny Goyale86f11f2017-06-06 14:33:18 -0700362 startLoaderForResults(loaderResults);
Winson Chungb8b2a5a2012-07-12 17:55:31 -0700363 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400364 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400365 }
Sunny Goyalb5b9ad62016-04-02 11:23:39 -0700366 return false;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400367 }
368
Sunny Goyale86f11f2017-06-06 14:33:18 -0700369 /**
370 * If there is already a loader task running, tell it to stop.
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530371 * @return true if an existing loader was stopped.
Sunny Goyale86f11f2017-06-06 14:33:18 -0700372 */
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530373 public boolean stopLoader() {
Joe Onorato36115782010-06-17 13:28:48 -0400374 synchronized (mLock) {
Sunny Goyale86f11f2017-06-06 14:33:18 -0700375 LoaderTask oldTask = mLoaderTask;
vadimtc8b09702020-01-27 17:44:44 -0800376 if (TestProtocol.sDebugTracing) {
377 Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "LauncherModel.stopLoader");
378 }
Sunny Goyale86f11f2017-06-06 14:33:18 -0700379 mLoaderTask = null;
380 if (oldTask != null) {
381 oldTask.stopLocked();
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530382 return true;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400383 }
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530384 return false;
Joe Onorato9c1289c2009-08-17 11:03:03 -0400385 }
Joe Onorato36115782010-06-17 13:28:48 -0400386 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400387
Sunny Goyale86f11f2017-06-06 14:33:18 -0700388 public void startLoaderForResults(LoaderResults results) {
389 synchronized (mLock) {
390 stopLoader();
Sunny Goyal9ae9b602019-12-18 19:29:00 +0530391 mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, mBgDataModel, results);
vadimtc8b09702020-01-27 17:44:44 -0800392 if (TestProtocol.sDebugTracing) {
393 Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
394 "LauncherModel.startLoaderForResults " + mLoaderTask);
395 }
Sunny Goyal51f220d2019-05-29 11:05:30 -0700396
397 // Always post the loader task, instead of running directly (even on same thread) so
398 // that we exit any nested synchronized blocks
Sunny Goyal6fe3eec2019-08-15 14:53:41 -0700399 MODEL_EXECUTOR.post(mLoaderTask);
Sunny Goyale86f11f2017-06-06 14:33:18 -0700400 }
401 }
402
Winson Chungd6519662018-02-16 03:23:51 +0000403 public void startLoaderForResultsIfNotLoaded(LoaderResults results) {
404 synchronized (mLock) {
405 if (!isModelLoaded()) {
406 Log.d(TAG, "Workspace not loaded, loading now");
407 startLoaderForResults(results);
408 }
409 }
410 }
411
Sunny Goyal045b4fa2019-09-20 12:51:37 -0700412 @Override
Mario Bertschler817afa32017-03-15 11:56:47 -0700413 public void onInstallSessionCreated(final PackageInstallInfo sessionInfo) {
Sunny Goyal045b4fa2019-09-20 12:51:37 -0700414 if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
415 enqueueModelUpdateTask(new BaseModelUpdateTask() {
416 @Override
417 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
418 apps.addPromiseApp(app.getContext(), sessionInfo);
419 bindApplicationsIfNeeded();
420 }
421 });
422 }
423 }
424
425 @Override
426 public void onSessionFailure(String packageName, UserHandle user) {
427 if (!FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()) {
428 return;
429 }
Sunny Goyale86f11f2017-06-06 14:33:18 -0700430 enqueueModelUpdateTask(new BaseModelUpdateTask() {
Mario Bertschler817afa32017-03-15 11:56:47 -0700431 @Override
432 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
Sunny Goyal045b4fa2019-09-20 12:51:37 -0700433 final IntSparseArrayMap<Boolean> removedIds = new IntSparseArrayMap<>();
434 synchronized (dataModel) {
435 for (ItemInfo info : dataModel.itemsIdMap) {
436 if (info instanceof WorkspaceItemInfo
437 && ((WorkspaceItemInfo) info).hasPromiseIconUi()
438 && user.equals(info.user)
439 && info.getIntent() != null
440 && TextUtils.equals(packageName, info.getIntent().getPackage())) {
441 removedIds.put(info.id, true /* remove */);
442 }
443 }
444 }
445
446 if (!removedIds.isEmpty()) {
447 deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false));
448 }
Mario Bertschler817afa32017-03-15 11:56:47 -0700449 }
450 });
451 }
452
Sunny Goyal045b4fa2019-09-20 12:51:37 -0700453 @Override
454 public void onPackageStateChanged(PackageInstallInfo installInfo) {
455 enqueueModelUpdateTask(new PackageInstallStateChangedTask(installInfo));
456 }
457
458 /**
459 * Updates the icons and label of all pending icons for the provided package name.
460 */
461 @Override
462 public void onUpdateSessionDisplay(PackageUserKey key, PackageInstaller.SessionInfo info) {
463 mApp.getIconCache().updateSessionCache(key, info);
464
465 HashSet<String> packages = new HashSet<>();
466 packages.add(key.mPackageName);
467 enqueueModelUpdateTask(new CacheDataUpdatedTask(
468 CacheDataUpdatedTask.OP_SESSION_UPDATE, key.mUser, packages));
469 }
470
Sunny Goyalc6e97692017-06-02 13:46:55 -0700471 public class LoaderTransaction implements AutoCloseable {
472
473 private final LoaderTask mTask;
474
475 private LoaderTransaction(LoaderTask task) throws CancellationException {
476 synchronized (mLock) {
477 if (mLoaderTask != task) {
478 throw new CancellationException("Loader already stopped");
479 }
480 mTask = task;
481 mIsLoaderTaskRunning = true;
482 mModelLoaded = false;
483 }
484 }
485
486 public void commit() {
487 synchronized (mLock) {
488 // Everything loaded bind the data.
489 mModelLoaded = true;
490 }
491 }
492
493 @Override
494 public void close() {
495 synchronized (mLock) {
496 // If we are still the last one to be scheduled, remove ourselves.
vadimtc8b09702020-01-27 17:44:44 -0800497 if (TestProtocol.sDebugTracing) {
498 Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
499 "LauncherModel.close " + mLoaderTask + ", " + mTask);
500 }
Sunny Goyalc6e97692017-06-02 13:46:55 -0700501 if (mLoaderTask == mTask) {
502 mLoaderTask = null;
503 }
504 mIsLoaderTaskRunning = false;
505 }
506 }
507 }
508
509 public LoaderTransaction beginLoader(LoaderTask task) throws CancellationException {
510 return new LoaderTransaction(task);
511 }
512
Joe Onorato36115782010-06-17 13:28:48 -0400513 /**
Sunny Goyal95f3d6b2016-08-10 16:09:29 -0700514 * Refreshes the cached shortcuts if the shortcut permission has changed.
515 * Current implementation simply reloads the workspace, but it can be optimized to
Sunny Goyal337c81f2019-12-10 12:19:13 -0800516 * use partial updates similar to {@link UserCache}
Sunny Goyal95f3d6b2016-08-10 16:09:29 -0700517 */
518 public void refreshShortcutsIfRequired() {
Sunny Goyal6fe3eec2019-08-15 14:53:41 -0700519 MODEL_EXECUTOR.getHandler().removeCallbacks(mShortcutPermissionCheckRunnable);
520 MODEL_EXECUTOR.post(mShortcutPermissionCheckRunnable);
Sunny Goyal95f3d6b2016-08-10 16:09:29 -0700521 }
522
523 /**
Sunny Goyal75b0f552015-05-20 21:57:06 -0700524 * Called when the icons for packages have been updated in the icon cache.
525 */
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800526 public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandle user) {
Sunny Goyal75b0f552015-05-20 21:57:06 -0700527 // If any package icon has changed (app was updated while launcher was dead),
528 // update the corresponding shortcuts.
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700529 enqueueModelUpdateTask(new CacheDataUpdatedTask(
530 CacheDataUpdatedTask.OP_CACHE_UPDATE, user, updatedPackages));
Sunny Goyal75b0f552015-05-20 21:57:06 -0700531 }
532
Sunny Goyalac8154a2018-09-26 12:00:30 -0700533 /**
534 * Called when the labels for the widgets has updated in the icon cache.
535 */
536 public void onWidgetLabelsUpdated(HashSet<String> updatedPackages, UserHandle user) {
537 enqueueModelUpdateTask(new BaseModelUpdateTask() {
538 @Override
539 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
540 dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, app);
541 bindUpdatedWidgets(dataModel);
542 }
543 });
544 }
545
Sunny Goyale86f11f2017-06-06 14:33:18 -0700546 public void enqueueModelUpdateTask(ModelUpdateTask task) {
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530547 task.init(mApp, this, mBgDataModel, mBgAllAppsList, mMainExecutor);
Sunny Goyal6fe3eec2019-08-15 14:53:41 -0700548 MODEL_EXECUTOR.execute(task);
Sunny Goyald3b87ef2016-07-28 12:11:54 -0700549 }
550
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700551 /**
552 * A task to be executed on the current callbacks on the UI thread.
553 * If there is no current callbacks, the task is ignored.
554 */
555 public interface CallbackTask {
Tony Wickhambfbf7f92016-05-19 11:19:39 -0700556
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700557 void execute(Callbacks callbacks);
Tony Wickhambfbf7f92016-05-19 11:19:39 -0700558 }
559
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700560 /**
561 * A runnable which changes/updates the data model of the launcher based on certain events.
562 */
Sunny Goyale86f11f2017-06-06 14:33:18 -0700563 public interface ModelUpdateTask extends Runnable {
Joe Onorato36115782010-06-17 13:28:48 -0400564
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700565 /**
Sunny Goyale86f11f2017-06-06 14:33:18 -0700566 * Called before the task is posted to initialize the internal state.
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700567 */
Sunny Goyale86f11f2017-06-06 14:33:18 -0700568 void init(LauncherAppState app, LauncherModel model,
569 BgDataModel dataModel, AllAppsList allAppsList, Executor uiExecutor);
Sunny Goyale0f58d72014-11-10 18:05:31 -0800570
Sunny Goyal2e1efb42016-03-03 16:58:55 -0800571 }
572
Sunny Goyal6bbf6002019-04-17 18:38:52 -0700573 public void updateAndBindWorkspaceItem(WorkspaceItemInfo si, ShortcutInfo info) {
Sunny Goyal95899162019-03-27 16:03:06 -0700574 updateAndBindWorkspaceItem(() -> {
Sunny Goyal83fd25e2018-07-09 16:47:01 -0700575 si.updateFromDeepShortcutInfo(info, mApp.getContext());
576 LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
Sunny Goyal3808a692019-10-25 13:41:28 -0700577 si.bitmap = li.createShortcutIcon(info);
Sunny Goyal83fd25e2018-07-09 16:47:01 -0700578 li.recycle();
579 return si;
Sunny Goyal1b072632017-01-18 11:30:23 -0800580 });
581 }
582
Sunny Goyal10923b32016-07-20 15:42:44 -0700583 /**
Sunny Goyal1cc1c9a2017-01-06 16:32:57 -0800584 * Utility method to update a shortcut on the background thread.
Sunny Goyal10923b32016-07-20 15:42:44 -0700585 */
Sunny Goyal95899162019-03-27 16:03:06 -0700586 public void updateAndBindWorkspaceItem(final Supplier<WorkspaceItemInfo> itemProvider) {
Sunny Goyale86f11f2017-06-06 14:33:18 -0700587 enqueueModelUpdateTask(new BaseModelUpdateTask() {
Sunny Goyal10923b32016-07-20 15:42:44 -0700588 @Override
Sunny Goyalf0ba8b72016-09-09 15:47:55 -0700589 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
Sunny Goyal95899162019-03-27 16:03:06 -0700590 WorkspaceItemInfo info = itemProvider.get();
Sunny Goyalf266deb2018-06-21 09:59:08 -0700591 getModelWriter().updateItemInDatabase(info);
Sunny Goyal95899162019-03-27 16:03:06 -0700592 ArrayList<WorkspaceItemInfo> update = new ArrayList<>();
Sunny Goyal10923b32016-07-20 15:42:44 -0700593 update.add(info);
Sunny Goyal95899162019-03-27 16:03:06 -0700594 bindUpdatedWorkspaceItems(update);
Sunny Goyal10923b32016-07-20 15:42:44 -0700595 }
596 });
597 }
598
Sunny Goyalc6e97692017-06-02 13:46:55 -0700599 public void refreshAndBindWidgetsAndShortcuts(@Nullable final PackageUserKey packageUser) {
Sunny Goyale86f11f2017-06-06 14:33:18 -0700600 enqueueModelUpdateTask(new BaseModelUpdateTask() {
Sunny Goyal2e1efb42016-03-03 16:58:55 -0800601 @Override
Sunny Goyalc6e97692017-06-02 13:46:55 -0700602 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
603 dataModel.widgetsModel.update(app, packageUser);
604 bindUpdatedWidgets(dataModel);
Sunny Goyal31860582015-09-18 08:38:57 -0700605 }
Sunny Goyal2e1efb42016-03-03 16:58:55 -0800606 });
Michael Jurkac402cd92013-05-20 15:49:32 +0200607 }
608
Hyunyoung Song3c7d9cb2017-01-30 15:11:27 -0800609 public void dumpState(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
610 if (args.length > 0 && TextUtils.equals(args[0], "--all")) {
611 writer.println(prefix + "All apps list: size=" + mBgAllAppsList.data.size());
612 for (AppInfo info : mBgAllAppsList.data) {
Sunny Goyal3808a692019-10-25 13:41:28 -0700613 writer.println(prefix + " title=\"" + info.title
614 + "\" bitmapIcon=" + info.bitmap.icon
Hyunyoung Song3c7d9cb2017-01-30 15:11:27 -0800615 + " componentName=" + info.componentName.getPackageName());
616 }
Joe Onorato36115782010-06-17 13:28:48 -0400617 }
Sunny Goyal9ae9b602019-12-18 19:29:00 +0530618 mBgDataModel.dump(prefix, fd, writer, args);
Joe Onoratobe386092009-11-17 17:32:16 -0800619 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800620
Sunny Goyala7a5bf32020-01-05 15:35:29 +0530621 /**
622 * Returns true if there are any callbacks attached to the model
623 */
624 public boolean hasCallbacks() {
625 synchronized (mCallbacksList) {
626 return !mCallbacksList.isEmpty();
627 }
628 }
629
630 /**
631 * Returns an array of currently attached callbacks
632 */
633 public Callbacks[] getCallbacks() {
634 synchronized (mCallbacksList) {
635 return mCallbacksList.toArray(new Callbacks[mCallbacksList.size()]);
636 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800637 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800638}