Merge "Revert "Decrease jank in all apps physics."" into ub-launcher3-dorval-polish
diff --git a/res/layout/notification.xml b/res/layout/notification.xml
index a03dd08..a183c92 100644
--- a/res/layout/notification.xml
+++ b/res/layout/notification.xml
@@ -66,7 +66,8 @@
android:layout_width="match_parent"
android:layout_height="@dimen/popup_item_divider_height"
android:background="?android:attr/listDivider"
- android:layout_below="@id/main_view"/>
+ android:layout_below="@id/main_view"
+ android:visibility="gone" />
<include layout="@layout/notification_footer"
android:id="@+id/footer"
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 84a8bce..70be7da 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -12,6 +12,7 @@
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.util.ContentWriter;
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@@ -52,7 +53,7 @@
final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
final int state;
- if (LauncherModel.isValidProvider(provider)) {
+ if (LoaderTask.isValidProvider(provider)) {
// This will ensure that we show 'Click to setup' UI if required.
state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
} else {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 265c7e3..48c5c56 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProviderOperation;
@@ -24,61 +23,40 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.PackageInstaller;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
-import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
-import android.util.LongSparseArray;
-import android.util.MutableInt;
import android.util.Pair;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dynamicui.ExtractionUtils;
-import com.android.launcher3.folder.Folder;
-import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.LauncherIcons;
-import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.CacheDataUpdatedTask;
import com.android.launcher3.model.ExtendedModelTask;
-import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.model.LoaderCursor;
import com.android.launcher3.model.LoaderResults;
+import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.PackageUpdatedTask;
-import com.android.launcher3.model.SdCardAvailableReceiver;
import com.android.launcher3.model.ShortcutsChangedTask;
import com.android.launcher3.model.UserLockStateChangedTask;
import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.LooperIdleLock;
-import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.MultiHashMap;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Provider;
@@ -89,12 +67,9 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
@@ -105,7 +80,7 @@
*/
public class LauncherModel extends BroadcastReceiver
implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
- static final boolean DEBUG_LOADERS = false;
+ static final boolean DEBUG_TASKS = false;
private static final boolean DEBUG_RECEIVER = false;
static final String TAG = "Launcher.Model";
@@ -113,7 +88,8 @@
private final MainThreadExecutor mUiExecutor = new MainThreadExecutor();
@Thunk final LauncherAppState mApp;
@Thunk final Object mLock = new Object();
- @Thunk LoaderTask mLoaderTask;
+ @Thunk
+ LoaderTask mLoaderTask;
@Thunk boolean mIsLoaderTaskRunning;
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@@ -610,761 +586,6 @@
}
/**
- * Runnable for the thread that loads the contents of the launcher:
- * - workspace icons
- * - widgets
- * - all apps icons
- * - deep shortcuts within apps
- */
- private static class LoaderTask implements Runnable {
- private final LauncherAppState mApp;
- private final AllAppsList mBgAllAppsList;
- private final BgDataModel mBgDataModel;
-
- private final LoaderResults mResults;
-
- private final LauncherAppsCompat mLauncherApps;
- private final UserManagerCompat mUserManager;
- private final DeepShortcutManager mShortcutManager;
- private final PackageInstallerCompat mPackageInstaller;
- private final AppWidgetManagerCompat mAppWidgetManager;
- private final IconCache mIconCache;
-
- private boolean mStopped;
-
- LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
- LoaderResults results) {
- mApp = app;
- mBgAllAppsList = bgAllAppsList;
- mBgDataModel = dataModel;
- mResults = results;
-
- mLauncherApps = LauncherAppsCompat.getInstance(mApp.getContext());
- mUserManager = UserManagerCompat.getInstance(mApp.getContext());
- mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext());
- mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());
- mAppWidgetManager = AppWidgetManagerCompat.getInstance(mApp.getContext());
- mIconCache = mApp.getIconCache();
- }
-
- private synchronized void waitForIdle() {
- // Wait until the either we're stopped or the other threads are done.
- // This way we don't start loading all apps until the workspace has settled
- // down.
- LooperIdleLock idleLock = new LooperIdleLock(this, Looper.getMainLooper());
- // Just in case mFlushingWorkerThread changes but we aren't woken up,
- // wait no longer than 1sec at a time
- while (!mStopped && idleLock.awaitLocked(1000));
- }
-
- private synchronized void verifyNotStopped() throws CancellationException {
- if (mStopped) {
- throw new CancellationException("Loader stopped");
- }
- }
-
- public void run() {
- synchronized (this) {
- // Skip fast if we are already stopped.
- if (mStopped) {
- return;
- }
- }
-
- try (LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
- long now = 0;
- if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
- loadWorkspace();
-
- verifyNotStopped();
- if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
- mResults.bindWorkspace();
-
- // Take a break
- if (DEBUG_LOADERS) {
- Log.d(TAG, "step 1 completed, wait for idle");
- now = SystemClock.uptimeMillis();
- }
- waitForIdle();
- if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
- verifyNotStopped();
-
- // second step
- if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
- loadAllApps();
-
- if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps");
- verifyNotStopped();
- mResults.bindAllApps();
-
- verifyNotStopped();
- if (DEBUG_LOADERS) Log.d(TAG, "step 2.3: Update icon cache");
- updateIconCache();
-
- // Take a break
- if (DEBUG_LOADERS) {
- Log.d(TAG, "step 2 completed, wait for idle");
- now = SystemClock.uptimeMillis();
- }
- waitForIdle();
- if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
- verifyNotStopped();
-
- // third step
- if (DEBUG_LOADERS) Log.d(TAG, "step 3.1: loading deep shortcuts");
- loadDeepShortcuts();
-
- verifyNotStopped();
- if (DEBUG_LOADERS) Log.d(TAG, "step 3.2: bind deep shortcuts");
- mResults.bindDeepShortcuts();
-
- // Take a break
- if (DEBUG_LOADERS) Log.d(TAG, "step 3 completed, wait for idle");
- waitForIdle();
- verifyNotStopped();
-
- // fourth step
- if (DEBUG_LOADERS) Log.d(TAG, "step 4.1: loading widgets");
- mBgDataModel.widgetsModel.update(mApp, null);
-
- verifyNotStopped();
- if (DEBUG_LOADERS) Log.d(TAG, "step 4.2: Binding widgets");
- mResults.bindWidgets();
-
- transaction.commit();
- } catch (CancellationException e) {
- // Loader stopped, ignore
- }
- }
-
- public synchronized void stopLocked() {
- mStopped = true;
- this.notify();
- }
-
- private void loadWorkspace() {
- if (LauncherAppState.PROFILE_STARTUP) {
- Trace.beginSection("Loading Workspace");
- }
-
- final Context context = mApp.getContext();
- final ContentResolver contentResolver = context.getContentResolver();
- final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
- final boolean isSafeMode = pmHelper.isSafeMode();
- final boolean isSdCardReady = Utilities.isBootCompleted();
- final MultiHashMap<UserHandle, String> pendingPackages = new MultiHashMap<>();
-
- boolean clearDb = false;
- try {
- ImportDataTask.performImportIfPossible(context);
- } catch (Exception e) {
- // Migration failed. Clear workspace.
- clearDb = true;
- }
-
- if (!clearDb && GridSizeMigrationTask.ENABLED &&
- !GridSizeMigrationTask.migrateGridIfNeeded(context)) {
- // Migration failed. Clear workspace.
- clearDb = true;
- }
-
- if (clearDb) {
- Log.d(TAG, "loadWorkspace: resetting launcher database");
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
- }
-
- Log.d(TAG, "loadWorkspace: loading default favorites");
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
-
- synchronized (mBgDataModel) {
- mBgDataModel.clear();
-
- final HashMap<String, Integer> installingPkgs =
- mPackageInstaller.updateAndGetActiveSessionCache();
- mBgDataModel.workspaceScreens.addAll(loadWorkspaceScreensDb(context));
-
- Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
- final LoaderCursor c = new LoaderCursor(contentResolver.query(
- LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
-
- HashMap<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null;
-
- try {
- final int appWidgetIdIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_ID);
- final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_PROVIDER);
- final int spanXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SPANY);
- final int rankIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.RANK);
- final int optionsIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.OPTIONS);
-
- final LongSparseArray<UserHandle> allUsers = c.allUsers;
- final LongSparseArray<Boolean> quietMode = new LongSparseArray<>();
- final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
- for (UserHandle user : mUserManager.getUserProfiles()) {
- long serialNo = mUserManager.getSerialNumberForUser(user);
- allUsers.put(serialNo, user);
- quietMode.put(serialNo, mUserManager.isQuietModeEnabled(user));
-
- boolean userUnlocked = mUserManager.isUserUnlocked(user);
-
- // We can only query for shortcuts when the user is unlocked.
- if (userUnlocked) {
- List<ShortcutInfoCompat> pinnedShortcuts =
- mShortcutManager.queryForPinnedShortcuts(null, user);
- if (mShortcutManager.wasLastCallSuccess()) {
- for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
- shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
- shortcut);
- }
- } else {
- // Shortcut manager can fail due to some race condition when the
- // lock state changes too frequently. For the purpose of the loading
- // shortcuts, consider the user is still locked.
- userUnlocked = false;
- }
- }
- unlockedUsers.put(serialNo, userUnlocked);
- }
-
- ShortcutInfo info;
- LauncherAppWidgetInfo appWidgetInfo;
- Intent intent;
- String targetPkg;
-
- FolderIconPreviewVerifier verifier =
- new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
- while (!mStopped && c.moveToNext()) {
- try {
- if (c.user == null) {
- // User has been deleted, remove the item.
- c.markDeleted("User has been deleted");
- continue;
- }
-
- boolean allowMissingTarget = false;
- switch (c.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- intent = c.parseIntent();
- if (intent == null) {
- c.markDeleted("Invalid or null intent");
- continue;
- }
-
- int disabledState = quietMode.get(c.serialNumber) ?
- ShortcutInfo.FLAG_DISABLED_QUIET_USER : 0;
- ComponentName cn = intent.getComponent();
- targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
-
- if (!Process.myUserHandle().equals(c.user)) {
- if (c.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- c.markDeleted("Legacy shortcuts are only allowed for default user");
- continue;
- } else if (c.restoreFlag != 0) {
- // Don't restore items for other profiles.
- c.markDeleted("Restore from managed profile not supported");
- continue;
- }
- }
- if (TextUtils.isEmpty(targetPkg) &&
- c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- c.markDeleted("Only legacy shortcuts can have null package");
- continue;
- }
-
- // If there is no target package, its an implicit intent
- // (legacy shortcut) which is always valid
- boolean validTarget = TextUtils.isEmpty(targetPkg) ||
- mLauncherApps.isPackageEnabledForProfile(targetPkg, c.user);
-
- if (cn != null && validTarget) {
- // If the apk is present and the shortcut points to a specific
- // component.
-
- // If the component is already present
- if (mLauncherApps.isActivityEnabledForProfile(cn, c.user)) {
- // no special handling necessary for this item
- c.markRestored();
- } else {
- if (c.hasRestoreFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
- // We allow auto install apps to have their intent
- // updated after an install.
- intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
- if (intent != null) {
- c.restoreFlag = 0;
- c.updater().put(
- LauncherSettings.Favorites.INTENT,
- intent.toUri(0)).commit();
- cn = intent.getComponent();
- } else {
- c.markDeleted("Unable to find a launch target");
- continue;
- }
- } else {
- // The app is installed but the component is no
- // longer available.
- c.markDeleted("Invalid component removed: " + cn);
- continue;
- }
- }
- }
- // else if cn == null => can't infer much, leave it
- // else if !validPkg => could be restored icon or missing sd-card
-
- if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
- // Points to a valid app (superset of cn != null) but the apk
- // is not available.
-
- if (c.restoreFlag != 0) {
- // Package is not yet available but might be
- // installed later.
- FileLog.d(TAG, "package not yet restored: " + targetPkg);
-
- if (c.hasRestoreFlag(ShortcutInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installingPkgs.containsKey(targetPkg)) {
- // App restore has started. Update the flag
- c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED;
- c.updater().commit();
- } else {
- c.markDeleted("Unrestored app removed: " + targetPkg);
- continue;
- }
- } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
- // Package is present but not available.
- disabledState |= ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else if (!isSdCardReady) {
- // SdCard is not ready yet. Package might get available,
- // once it is ready.
- Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
- pendingPackages.addToList(c.user, targetPkg);
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else {
- // Do not wait for external media load anymore.
- c.markDeleted("Invalid package removed: " + targetPkg);
- continue;
- }
- }
-
- if (validTarget) {
- // The shortcut points to a valid target (either no target
- // or something which is ready to be used)
- c.markRestored();
- }
-
- boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() &&
- !verifier.isItemInPreview(c.getInt(rankIndex));
-
- if (c.restoreFlag != 0) {
- // Already verified above that user is same as default user
- info = c.getRestoredItemInfo(intent);
- } else if (c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = c.getAppShortcutInfo(
- intent, allowMissingTarget, useLowResIcon);
- } else if (c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-
- ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
- if (unlockedUsers.get(c.serialNumber)) {
- ShortcutInfoCompat pinnedShortcut =
- shortcutKeyToPinnedShortcuts.get(key);
- if (pinnedShortcut == null) {
- // The shortcut is no longer valid.
- c.markDeleted("Pinned shortcut not found");
- continue;
- }
- info = new ShortcutInfo(pinnedShortcut, context);
- info.iconBitmap = LauncherIcons
- .createShortcutIcon(pinnedShortcut, context);
- if (pmHelper.isAppSuspended(
- pinnedShortcut.getPackage(), info.user)) {
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
- }
- intent = info.intent;
- } else {
- // Create a shortcut info in disabled mode for now.
- info = c.loadSimpleShortcut();
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
- }
- } else { // item type == ITEM_TYPE_SHORTCUT
- info = c.loadSimpleShortcut();
-
- // Shortcuts are only available on the primary profile
- if (!TextUtils.isEmpty(targetPkg)
- && pmHelper.isAppSuspended(targetPkg, c.user)) {
- disabledState |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
- }
-
- // App shortcuts that used to be automatically added to Launcher
- // didn't always have the correct intent flags set, so do that
- // here
- if (intent.getAction() != null &&
- intent.getCategories() != null &&
- intent.getAction().equals(Intent.ACTION_MAIN) &&
- intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- }
-
- if (info != null) {
- c.applyCommonProperties(info);
-
- info.intent = intent;
- info.rank = c.getInt(rankIndex);
- info.spanX = 1;
- info.spanY = 1;
- info.isDisabled |= disabledState;
- if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
- }
-
- if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
- Integer progress = installingPkgs.get(targetPkg);
- if (progress != null) {
- info.setInstallProgress(progress);
- } else {
- info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
- }
- }
-
- c.checkAndAddItem(info, mBgDataModel);
- } else {
- throw new RuntimeException("Unexpected null ShortcutInfo");
- }
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
- c.applyCommonProperties(folderInfo);
-
- // Do not trim the folder label, as is was set by the user.
- folderInfo.title = c.getString(c.titleIndex);
- folderInfo.spanX = 1;
- folderInfo.spanY = 1;
- folderInfo.options = c.getInt(optionsIndex);
-
- // no special handling required for restored folders
- c.markRestored();
-
- c.checkAndAddItem(folderInfo, mBgDataModel);
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
- // Read all Launcher-specific widget details
- boolean customWidget = c.itemType ==
- LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
- int appWidgetId = c.getInt(appWidgetIdIndex);
- String savedProvider = c.getString(appWidgetProviderIndex);
-
- final ComponentName component =
- ComponentName.unflattenFromString(savedProvider);
-
- final boolean isIdValid = !c.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
- final boolean wasProviderReady = !c.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
- if (widgetProvidersMap == null) {
- widgetProvidersMap = mAppWidgetManager.getAllProvidersMap();
- }
- final AppWidgetProviderInfo provider = widgetProvidersMap.get(
- new ComponentKey(
- ComponentName.unflattenFromString(savedProvider),
- c.user));
-
- final boolean isProviderReady = isValidProvider(provider);
- if (!isSafeMode && !customWidget &&
- wasProviderReady && !isProviderReady) {
- c.markDeleted(
- "Deleting widget that isn't installed anymore: "
- + provider);
- } else {
- if (isProviderReady) {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
-
- // The provider is available. So the widget is either
- // available or not available. We do not need to track
- // any future restore updates.
- int status = c.restoreFlag &
- ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- if (!wasProviderReady) {
- // If provider was not previously ready, update the
- // status and UI flag.
-
- // Id would be valid only if the widget restore broadcast was received.
- if (isIdValid) {
- status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- } else {
- status &= ~LauncherAppWidgetInfo
- .FLAG_PROVIDER_NOT_READY;
- }
- }
- appWidgetInfo.restoreStatus = status;
- } else {
- Log.v(TAG, "Widget restore pending id=" + c.id
- + " appWidgetId=" + appWidgetId
- + " status =" + c.restoreFlag);
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- component);
- appWidgetInfo.restoreStatus = c.restoreFlag;
- Integer installProgress = installingPkgs.get(component.getPackageName());
-
- if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installProgress != null) {
- // App restore has started. Update the flag
- appWidgetInfo.restoreStatus |=
- LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- } else if (!isSafeMode) {
- c.markDeleted("Unrestored widget removed: " + component);
- continue;
- }
-
- appWidgetInfo.installProgress =
- installProgress == null ? 0 : installProgress;
- }
- if (appWidgetInfo.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
- appWidgetInfo.bindOptions = c.parseIntent();
- }
-
- c.applyCommonProperties(appWidgetInfo);
- appWidgetInfo.spanX = c.getInt(spanXIndex);
- appWidgetInfo.spanY = c.getInt(spanYIndex);
- appWidgetInfo.user = c.user;
-
- if (!c.isOnWorkspaceOrHotseat()) {
- c.markDeleted("Widget found where container != " +
- "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
- continue;
- }
-
- if (!customWidget) {
- String providerName =
- appWidgetInfo.providerName.flattenToString();
- if (!providerName.equals(savedProvider) ||
- (appWidgetInfo.restoreStatus != c.restoreFlag)) {
- c.updater()
- .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
- providerName)
- .put(LauncherSettings.Favorites.RESTORED,
- appWidgetInfo.restoreStatus)
- .commit();
- }
- }
-
- if (appWidgetInfo.restoreStatus !=
- LauncherAppWidgetInfo.RESTORE_COMPLETED) {
- String pkg = appWidgetInfo.providerName.getPackageName();
- appWidgetInfo.pendingItemInfo = new PackageItemInfo(pkg);
- appWidgetInfo.pendingItemInfo.user = appWidgetInfo.user;
- mIconCache.getTitleAndIconForApp(
- appWidgetInfo.pendingItemInfo, false);
- }
-
- c.checkAndAddItem(appWidgetInfo, mBgDataModel);
- }
- break;
- }
- } catch (Exception e) {
- Log.e(TAG, "Desktop items loading interrupted", e);
- }
- }
- } finally {
- Utilities.closeSilently(c);
- }
-
- // Break early if we've stopped loading
- if (mStopped) {
- mBgDataModel.clear();
- return;
- }
-
- // Remove dead items
- if (c.commitDeleted()) {
- // Remove any empty folder
- ArrayList<Long> deletedFolderIds = (ArrayList<Long>) LauncherSettings.Settings
- .call(contentResolver,
- LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
- .getSerializable(LauncherSettings.Settings.EXTRA_VALUE);
- for (long folderId : deletedFolderIds) {
- mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
- mBgDataModel.folders.remove(folderId);
- mBgDataModel.itemsIdMap.remove(folderId);
- }
-
- // Remove any ghost widgets
- LauncherSettings.Settings.call(contentResolver,
- LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
- }
-
- // Unpin shortcuts that don't exist on the workspace.
- HashSet<ShortcutKey> pendingShortcuts =
- InstallShortcutReceiver.getPendingShortcuts(context);
- for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
- MutableInt numTimesPinned = mBgDataModel.pinnedShortcutCounts.get(key);
- if ((numTimesPinned == null || numTimesPinned.value == 0)
- && !pendingShortcuts.contains(key)) {
- // Shortcut is pinned but doesn't exist on the workspace; unpin it.
- mShortcutManager.unpinShortcut(key);
- }
- }
-
- FolderIconPreviewVerifier verifier =
- new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
- // Sort the folder items and make sure all items in the preview are high resolution.
- for (FolderInfo folder : mBgDataModel.folders) {
- Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
- verifier.setFolderInfo(folder);
-
- int numItemsInPreview = 0;
- for (ShortcutInfo info : folder.contents) {
- if (info.usingLowResIcon
- && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && verifier.isItemInPreview(info.rank)) {
- mIconCache.getTitleAndIcon(info, false);
- numItemsInPreview++;
- }
-
- if (numItemsInPreview >= FolderIcon.NUM_ITEMS_IN_PREVIEW) {
- break;
- }
- }
- }
-
- c.commitRestoredItems();
- if (!isSdCardReady && !pendingPackages.isEmpty()) {
- context.registerReceiver(
- new SdCardAvailableReceiver(mApp, pendingPackages),
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED),
- null,
- sWorker);
- }
-
- // Remove any empty screens
- ArrayList<Long> unusedScreens = new ArrayList<>(mBgDataModel.workspaceScreens);
- for (ItemInfo item: mBgDataModel.itemsIdMap) {
- long screenId = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- unusedScreens.contains(screenId)) {
- unusedScreens.remove(screenId);
- }
- }
-
- // If there are any empty screens remove them, and update.
- if (unusedScreens.size() != 0) {
- mBgDataModel.workspaceScreens.removeAll(unusedScreens);
- updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens);
- }
- }
- if (LauncherAppState.PROFILE_STARTUP) {
- Trace.endSection();
- }
- }
-
- private void updateIconCache() {
- // Ignore packages which have a promise icon.
- HashSet<String> packagesToIgnore = new HashSet<>();
- synchronized (mBgDataModel) {
- for (ItemInfo info : mBgDataModel.itemsIdMap) {
- if (info instanceof ShortcutInfo) {
- ShortcutInfo si = (ShortcutInfo) info;
- if (si.isPromise() && si.getTargetComponent() != null) {
- packagesToIgnore.add(si.getTargetComponent().getPackageName());
- }
- } else if (info instanceof LauncherAppWidgetInfo) {
- LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;
- if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
- packagesToIgnore.add(lawi.providerName.getPackageName());
- }
- }
- }
- }
- mIconCache.updateDbIcons(packagesToIgnore);
- }
-
- private void loadAllApps() {
- final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
- final List<UserHandle> profiles = mUserManager.getUserProfiles();
-
- // Clear the list of apps
- mBgAllAppsList.clear();
- for (UserHandle user : profiles) {
- // Query for the set of apps
- final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
- if (DEBUG_LOADERS) {
- Log.d(TAG, "getActivityList took "
- + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
- Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
- }
- // Fail if we don't have any apps
- // TODO: Fix this. Only fail for the current user.
- if (apps == null || apps.isEmpty()) {
- return;
- }
- boolean quietMode = mUserManager.isQuietModeEnabled(user);
- // Create the ApplicationInfos
- for (int i = 0; i < apps.size(); i++) {
- LauncherActivityInfo app = apps.get(i);
- // This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
- }
-
- ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
- }
-
- if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
- // get all active sessions and add them to the all apps list
- for (PackageInstaller.SessionInfo info :
- mPackageInstaller.getAllVerifiedSessions()) {
- mBgAllAppsList.addPromiseApp(mApp.getContext(),
- PackageInstallInfo.fromInstallingState(info));
- }
- }
-
- mBgAllAppsList.added = new ArrayList<>();
- if (DEBUG_LOADERS) {
- Log.d(TAG, "All apps loaded in in "
- + (SystemClock.uptimeMillis() - loadTime) + "ms");
- }
- }
-
- private void loadDeepShortcuts() {
- mBgDataModel.deepShortcutMap.clear();
- mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission();
- if (mBgDataModel.hasShortcutHostPermission) {
- for (UserHandle user : mUserManager.getUserProfiles()) {
- if (mUserManager.isUserUnlocked(user)) {
- List<ShortcutInfoCompat> shortcuts =
- mShortcutManager.queryForAllShortcuts(user);
- mBgDataModel.updateDeepShortcutMap(null, user, shortcuts);
- }
- }
- }
- }
- }
-
- /**
* Refreshes the cached shortcuts if the shortcut permission has changed.
* Current implementation simply reloads the workspace, but it can be optimized to
* use partial updates similar to {@link UserManagerCompat}
@@ -1417,7 +638,7 @@
@Override
public final void run() {
if (!mModel.mModelLoaded) {
- if (DEBUG_LOADERS) {
+ if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
}
// Loader has not yet run.
@@ -1489,11 +710,6 @@
});
}
- static boolean isValidProvider(AppWidgetProviderInfo provider) {
- return (provider != null) && (provider.provider != null)
- && (provider.provider.getPackageName() != null);
- }
-
public void dumpState(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
if (args.length > 0 && TextUtils.equals(args[0], "--all")) {
writer.println(prefix + "All apps list: size=" + mBgAllAppsList.data.size());
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
index 5a0e78b..21d5b27 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
@@ -23,6 +23,7 @@
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.Pair;
+import android.util.Range;
import android.util.SparseIntArray;
import com.android.launcher3.R;
@@ -51,16 +52,18 @@
private static final float FIT_WEIGHT_S = 1.0f;
private static final float FIT_WEIGHT_L = 10.0f;
+ // When extracting the main color, only consider colors
+ // present in at least MIN_COLOR_OCCURRENCE of the image
private static final float MIN_COLOR_OCCURRENCE = 0.1f;
- private static final float MIN_LUMINOSITY = 0.5f;
- public ColorExtractionAlgorithm() {
- }
+ // Temporary variable to avoid allocations
+ private final float[] mTmpHSL = new float[3];
public @Nullable Pair<Integer, Integer> extractInto(WallpaperColorsCompat wallpaperColors) {
if (wallpaperColors == null) {
return null;
}
+
SparseIntArray colorsArray = wallpaperColors.getColors();
if (colorsArray.size() == 0) {
return null;
@@ -71,13 +74,12 @@
// and replaces the original palette
List<Pair<Integer, Integer>> colors = new ArrayList<>(colorsArray.size());
- for (int i = colorsArray.size() - 1; i >= 0; i --) {
+ for (int i = colorsArray.size() - 1; i >= 0; i--) {
colors.add(Pair.create(colorsArray.keyAt(i), colorsArray.valueAt(i)));
}
// First find the most representative color in the image
populationSort(colors);
-
// Calculate total
int total = 0;
for (Pair<Integer, Integer> weightedColor : colors) {
@@ -96,53 +98,80 @@
int colorValue = weightedColor.first;
ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue),
Color.blue(colorValue), hsl);
- if (hsl[2] > MIN_LUMINOSITY) {
+
+ // Stop when we find a color that meets our criteria
+ if (!isBlacklisted(hsl)) {
bestColor = weightedColor;
+ break;
}
}
- // Fallback to first color
+ // Fail if not found
if (bestColor == null) {
- bestColor = colors.get(0);
+ return null;
}
int colorValue = bestColor.first;
ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue),
hsl);
- hsl[0] /= 360.0f; // normalize
- // TODO, we're finding a tonal palette for a hue, not all components
+ // The Android HSL definition requires the hue to go from 0 to 360 but
+ // the Material Tonal Palette defines hues from 0 to 1.
+ hsl[0] /= 360f;
+
+ // Find the palette that contains the closest color
TonalPalette palette = findTonalPalette(hsl[0]);
- // Fall back to population sort if we couldn't find a tonal palette
if (palette == null) {
Log.w(TAG, "Could not find a tonal palette!");
return null;
}
+ // Figure out what's the main color index in the optimal palette
int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]);
if (fitIndex == -1) {
Log.w(TAG, "Could not find best fit!");
return null;
}
+
+ // Generate the 10 colors palette by offsetting each one of them
float[] h = fit(palette.h, hsl[0], fitIndex,
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
+ final int textInversionIndex = h.length - 3;
- hsl[0] = fract(h[0]) * 360.0f;
- hsl[1] = s[0];
- hsl[2] = l[0];
- int mainColor = ColorUtils.HSLToColor(hsl);
+ // best fit + a 2 colors offset
+ int primaryIndex = fitIndex;
+ int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
+ int mainColor = getColorInt(primaryIndex, h, s, l);
+ int secondaryColor = getColorInt(secondaryIndex, h, s, l);
- hsl[0] = fract(h[1]) * 360.0f;
- hsl[1] = s[1];
- hsl[2] = l[1];
- int secondaryColor = ColorUtils.HSLToColor(hsl);
return new Pair<>(mainColor, secondaryColor);
}
+ private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
+ mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
+ mTmpHSL[1] = s[fitIndex];
+ mTmpHSL[2] = l[fitIndex];
+ return ColorUtils.HSLToColor(mTmpHSL);
+ }
+
+ /**
+ * Checks if a given color exists in the blacklist
+ * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1)
+ * @return true if color should be avoided
+ */
+ private boolean isBlacklisted(float[] hsl) {
+ for (ColorRange badRange: BLACKLISTED_COLORS) {
+ if (badRange.containsColor(hsl[0], hsl[1], hsl[2])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static void populationSort(@NonNull List<Pair<Integer, Integer>> wallpaperColors) {
Collections.sort(wallpaperColors, new Comparator<Pair<Integer, Integer>>() {
@Override
@@ -160,7 +189,7 @@
* @param index which index to calculate the delta against
* @param min minimum accepted value (clamp)
* @param max maximum accepted value (clamp)
- * @return
+ * @return new shifted palette
*/
private static float[] fit(float[] data, float v, int index, float min, float max) {
float[] fitData = new float[data.length];
@@ -272,44 +301,460 @@
// Data definition of Material Design tonal palettes
// When the sort type is set to TONAL, these palettes are used to find
- // a best fist. Each palette is defined as 10 HSL colors
+ // a best fit. Each palette is defined as 22 HSL colors
private static final TonalPalette[] TONAL_PALETTES = {
- // Orange
new TonalPalette(
- new float[] { 0.028f, 0.042f, 0.053f, 0.061f, 0.078f, 0.1f, 0.111f, 0.111f, 0.111f, 0.111f },
- new float[] { 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f },
- new float[] { 0.5f, 0.53f, 0.54f, 0.55f, 0.535f, 0.52f, 0.5f, 0.63f, 0.75f, 0.85f }
+ new float[]{0.991f, 0.9833333333333333f, 0f, 0f, 0f, 0.01134380453752181f,
+ 0.015625000000000003f, 0.024193548387096798f, 0.027397260273972573f,
+ 0.017543859649122865f},
+ new float[]{1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.2f, 0.27450980392156865f, 0.34901960784313724f,
+ 0.4235294117647059f, 0.5490196078431373f, 0.6254901960784314f,
+ 0.6862745098039216f, 0.7568627450980392f, 0.8568627450980393f,
+ 0.9254901960784314f}
),
- // Yellow
new TonalPalette(
- new float[] { 0.111f, 0.111f, 0.125f, 0.133f, 0.139f, 0.147f, 0.156f, 0.156f, 0.156f, 0.156f },
- new float[] { 1f, 0.942f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f },
- new float[] { 0.43f, 0.484f, 0.535f, 0.555f, 0.57f, 0.575f, 0.595f, 0.715f, 0.78f, 0.885f }
+ new float[]{0.6385767790262171f, 0.6301169590643275f, 0.6223958333333334f,
+ 0.6151079136690647f, 0.6065400843881856f, 0.5986964618249534f,
+ 0.5910746812386157f, 0.5833333333333334f, 0.5748031496062993f,
+ 0.5582010582010583f},
+ new float[]{1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
+ 0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f,
+ 1f, 1f, 1f},
+ new float[]{0.17450980392156862f, 0.2235294117647059f, 0.2784313725490196f,
+ 0.3352941176470588f, 0.388235294117647f, 0.44901960784313727f,
+ 0.5392156862745098f, 0.6509803921568628f, 0.7509803921568627f,
+ 0.8764705882352941f}
),
- // Green
new TonalPalette(
- new float[] { 0.325f, 0.336f, 0.353f, 0.353f, 0.356f, 0.356f, 0.356f, 0.356f, 0.356f, 0.356f },
- new float[] { 1f, 1f, 0.852f, 0.754f, 0.639f, 0.667f, 0.379f, 0.542f, 1f, 1f },
- new float[] { 0.06f, 0.1f, 0.151f, 0.194f, 0.25f, 0.312f, 0.486f, 0.651f, 0.825f, 0.885f }
+ new float[]{0.5669934640522876f, 0.5748031496062993f,
+ 0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f,
+ 0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f,
+ 0.508080808080808f, 0.5f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f, 1f},
+ new float[]{0.2f, 0.24901960784313726f, 0.27450980392156865f,
+ 0.30392156862745096f, 0.34901960784313724f, 0.4137254901960784f,
+ 0.47647058823529415f, 0.5352941176470588f, 0.6764705882352942f, 0.8f}
),
- // Blue
new TonalPalette(
- new float[] { 0.631f, 0.603f, 0.592f, 0.586f, 0.572f, 0.544f, 0.519f, 0.519f, 0.519f, 0.519f },
- new float[] { 0.852f, 1f, 0.887f, 0.852f, 0.871f, 0.907f, 0.949f, 0.934f, 0.903f, 0.815f },
- new float[] { 0.34f, 0.38f, 0.482f, 0.497f, 0.536f, 0.571f, 0.608f, 0.696f, 0.794f, 0.892f }
+ new float[]{0.5082304526748972f, 0.5069444444444444f, 0.5f, 0.5f,
+ 0.5f, 0.48724954462659376f, 0.4800347222222222f,
+ 0.4755134281200632f, 0.4724409448818897f, 0.4671052631578947f},
+ new float[]{1f, 0.8888888888888887f, 0.9242424242424242f, 1f, 1f,
+ 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
+ new float[]{0.1588235294117647f, 0.21176470588235297f,
+ 0.25882352941176473f, 0.3f, 0.34901960784313724f,
+ 0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f,
+ 0.7509803921568627f, 0.8509803921568627f}
),
- // Purple
new TonalPalette(
- new float[] { 0.839f, 0.831f, 0.825f, 0.819f, 0.803f, 0.803f, 0.772f, 0.772f, 0.772f, 0.772f },
- new float[] { 1f, 1f, 1f, 1f, 1f, 1f, 0.769f, 0.701f, 0.612f, 0.403f },
- new float[] { 0.125f, 0.15f, 0.2f, 0.245f, 0.31f, 0.36f, 0.567f, 0.666f, 0.743f, 0.833f }
+ new float[]{0.3333333333333333f, 0.3333333333333333f,
+ 0.34006734006734f, 0.34006734006734f, 0.34006734006734f,
+ 0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f,
+ 0.3467741935483871f, 0.3703703703703704f},
+ new float[]{0.6703296703296703f, 0.728813559322034f,
+ 0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
+ 0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
+ new float[]{0.1784313725490196f, 0.23137254901960785f,
+ 0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
+ 0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
+ 0.8784313725490196f, 0.9294117647058824f}
),
- // Red
new TonalPalette(
- new float[] { 0.964f, 0.975f, 0.975f, 0.975f, 0.972f, 0.992f, 1.003f, 1.011f, 1.011f, 1.011f },
- new float[] { 0.869f, 0.802f, 0.739f, 0.903f, 1f, 1f, 1f, 1f, 1f, 1f },
- new float[] { 0.241f, 0.316f, 0.46f, 0.586f, 0.655f, 0.7f, 0.75f, 0.8f, 0.84f, 0.88f }
+ new float[]{0.162280701754386f, 0.15032679738562088f,
+ 0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f,
+ 0.17824074074074076f, 0.18674698795180725f,
+ 0.18692449355432778f, 0.1946778711484594f, 0.18604651162790695f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.14901960784313725f, 0.2f, 0.24901960784313726f,
+ 0.30392156862745096f, 0.3784313725490196f, 0.4235294117647059f,
+ 0.48823529411764705f, 0.6450980392156863f, 0.7666666666666666f,
+ 0.8313725490196078f}
+ ),
+ new TonalPalette(
+ new float[]{0.10619469026548674f, 0.11924686192468618f,
+ 0.13046448087431692f, 0.14248366013071895f, 0.1506024096385542f,
+ 0.16220238095238093f, 0.16666666666666666f,
+ 0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.44313725490196076f, 0.46862745098039216f,
+ 0.47843137254901963f, 0.5f, 0.5117647058823529f,
+ 0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f,
+ 0.8509803921568627f, 0.9f}
+ ),
+ new TonalPalette(
+ new float[]{0.03561253561253561f, 0.05098039215686275f,
+ 0.07516339869281045f, 0.09477124183006536f, 0.1150326797385621f,
+ 0.134640522875817f, 0.14640522875816991f, 0.1582397003745319f,
+ 0.15773809523809523f, 0.15359477124183002f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.4588235294117647f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
+ 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
+ ),
+ new TonalPalette(
+ new float[]{0.9596491228070175f, 0.9593837535014005f,
+ 0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f,
+ 0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f,
+ 0.9754098360655739f, 0.9824561403508771f},
+ new float[]{0.84070796460177f, 0.8206896551724138f,
+ 0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f,
+ 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.22156862745098038f, 0.2843137254901961f,
+ 0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f,
+ 0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f,
+ 0.9254901960784314f}
+ ),
+ new TonalPalette(
+ new float[]{0.841025641025641f, 0.8333333333333334f,
+ 0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
+ 0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
+ 0.7771084337349398f, 0.7747747747747749f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f,
+ 0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
+ new float[]{0.12745098039215685f, 0.15490196078431373f,
+ 0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
+ 0.36470588235294116f, 0.44901960784313727f,
+ 0.6568627450980392f, 0.7470588235294118f, 0.8450980392156863f}
+ ),
+ new TonalPalette(
+ new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
+ new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
+ new float[]{0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
+ 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
+ 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
+ ),
+ new TonalPalette(
+ new float[]{0.955952380952381f, 0.9681069958847737f,
+ 0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
+ 0.009057971014492771f, 0.026748971193415648f,
+ 0.041666666666666616f, 0.05303030303030304f},
+ new float[]{1f, 0.8350515463917526f, 0.6929460580912863f,
+ 0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f,
+ 0.8070175438596495f, 0.9310344827586209f, 1f, 1f},
+ new float[]{0.27450980392156865f, 0.3803921568627451f,
+ 0.4725490196078432f, 0.5549019607843138f, 0.6313725490196078f,
+ 0.707843137254902f, 0.7764705882352941f, 0.8294117647058823f,
+ 0.9058823529411765f, 0.9568627450980391f}
+ ),
+ new TonalPalette(
+ new float[]{0.7514619883040936f, 0.7679738562091503f,
+ 0.7802083333333333f, 0.7844311377245509f, 0.796875f,
+ 0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f,
+ 0.8562091503267975f, 0.8666666666666667f},
+ new float[]{1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
+ 0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f,
+ 0.9560439560439562f, 1f, 1f},
+ new float[]{0.2235294117647059f, 0.3f, 0.38431372549019605f,
+ 0.492156862745098f, 0.5843137254901961f, 0.6647058823529411f,
+ 0.7333333333333334f, 0.8215686274509804f, 0.9f,
+ 0.9411764705882353f}
+ ),
+ new TonalPalette(
+ new float[]{0.6666666666666666f, 0.6666666666666666f,
+ 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
+ 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
+ 0.6666666666666666f, 0.6666666666666666f},
+ new float[]{0.24590163934426232f, 0.17880794701986752f,
+ 0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f,
+ 0.16756756756756758f, 0.20312500000000017f,
+ 0.26086956521739135f, 0.29999999999999966f, 0.5000000000000004f},
+ new float[]{0.2392156862745098f, 0.296078431372549f,
+ 0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f,
+ 0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f,
+ 0.8823529411764706f, 0.9372549019607843f}
+ ),
+ new TonalPalette(
+ new float[]{0.9678571428571429f, 0.9944812362030905f, 0f, 0f,
+ 0.0047348484848484815f, 0.00316455696202532f, 0f,
+ 0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f},
+ new float[]{1f, 0.7023255813953488f, 0.6638655462184874f,
+ 0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f,
+ 0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f,
+ 0.8181818181818189f},
+ new float[]{0.27450980392156865f, 0.4215686274509804f,
+ 0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f,
+ 0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f,
+ 0.892156862745098f, 0.9568627450980391f}
+ ),
+ new TonalPalette(
+ new float[]{0.9052287581699346f, 0.9112021857923498f, 0.9270152505446624f,
+ 0.9343137254901961f, 0.9391534391534391f, 0.9437984496124031f,
+ 0.943661971830986f, 0.9438943894389439f, 0.9426229508196722f,
+ 0.9444444444444444f},
+ new float[]{1f, 0.8133333333333332f, 0.7927461139896375f, 0.7798165137614679f,
+ 0.7777777777777779f, 0.8190476190476191f, 0.8255813953488372f,
+ 0.8211382113821142f, 0.8133333333333336f, 0.8000000000000006f},
+ new float[]{0.2f, 0.29411764705882354f, 0.3784313725490196f,
+ 0.42745098039215684f, 0.4764705882352941f, 0.5882352941176471f,
+ 0.6627450980392157f, 0.7588235294117647f, 0.8529411764705882f,
+ 0.9411764705882353f}
+ ),
+ new TonalPalette(
+ new float[]{0.6884057971014492f, 0.6974789915966387f, 0.7079889807162534f,
+ 0.7154471544715447f, 0.7217741935483872f, 0.7274143302180687f,
+ 0.7272727272727273f, 0.7258064516129031f, 0.7252252252252251f,
+ 0.7333333333333333f},
+ new float[]{0.8214285714285715f, 0.6878612716763006f, 0.6080402010050251f,
+ 0.5774647887323943f, 0.5391304347826086f, 0.46724890829694316f,
+ 0.4680851063829788f, 0.462686567164179f, 0.45679012345678977f,
+ 0.4545454545454551f},
+ new float[]{0.2196078431372549f, 0.33921568627450976f, 0.39019607843137255f,
+ 0.4176470588235294f, 0.45098039215686275f,
+ 0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f,
+ 0.8411764705882353f, 0.9352941176470588f}
+ ),
+ new TonalPalette(
+ new float[]{0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
+ 0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f,
+ 0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f,
+ 0.6428571428571429f},
+ new float[]{0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
+ 0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f,
+ 0.44360902255639095f,
+ 0.4499999999999997f, 0.4375000000000006f},
+ new float[]{0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
+ 0.40588235294117647f, 0.44705882352941173f,
+ 0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f,
+ 0.8431372549019608f, 0.9372549019607843f}
+ ),
+ new TonalPalette(
+ new float[]{0.46732026143790845f, 0.4718614718614719f, 0.4793650793650794f,
+ 0.48071625344352614f, 0.4829683698296837f, 0.484375f,
+ 0.4841269841269842f, 0.48444444444444457f, 0.48518518518518516f,
+ 0.4907407407407408f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
+ 0.41899441340782106f, 0.4128440366972478f,
+ 0.4090909090909088f},
+ new float[]{0.1f, 0.15098039215686274f, 0.20588235294117646f,
+ 0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f,
+ 0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f}
+ ),
+ new TonalPalette(
+ new float[]{0.5444444444444444f, 0.5555555555555556f, 0.5555555555555556f,
+ 0.553763440860215f, 0.5526315789473684f, 0.5555555555555556f,
+ 0.5555555555555555f, 0.5555555555555556f, 0.5512820512820514f,
+ 0.5666666666666667f},
+ new float[]{0.24590163934426232f, 0.19148936170212766f, 0.1791044776119403f,
+ 0.18343195266272191f, 0.18446601941747576f,
+ 0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f,
+ 0.15662650602409653f, 0.151515151515151f},
+ new float[]{0.1196078431372549f, 0.1843137254901961f, 0.2627450980392157f,
+ 0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f,
+ 0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f,
+ 0.9352941176470588f}
+ ),
+ new TonalPalette(
+ new float[]{0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
+ 0.03947368421052631f, 0.04166666666666668f,
+ 0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f,
+ 0.04444444444444459f, 0.05555555555555529f},
+ new float[]{0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
+ 0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f,
+ 0.15315315315315312f, 0.15189873417721522f,
+ 0.15789473684210534f, 0.15789473684210542f},
+ new float[]{0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
+ 0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f,
+ 0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f,
+ 0.9254901960784314f}
+ ),
+ new TonalPalette(
+ new float[]{0.050884955752212385f, 0.07254901960784313f, 0.0934640522875817f,
+ 0.10457516339869281f, 0.11699346405228758f,
+ 0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f,
+ 0.12500000000000003f, 0.12777777777777777f},
+ new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+ new float[]{0.44313725490196076f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5784313725490196f,
+ 0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f,
+ 0.9411764705882353f}
)
};
+ @SuppressWarnings("WeakerAccess")
+ static final ColorRange[] BLACKLISTED_COLORS = new ColorRange[] {
+
+ // Red
+ new ColorRange(
+ new Range<>(0f, 20f) /* H */,
+ new Range<>(0.7f, 1f) /* S */,
+ new Range<>(0.21f, 0.79f)) /* L */,
+ new ColorRange(
+ new Range<>(0f, 20f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.355f, 0.653f)),
+
+ // Red Orange
+ new ColorRange(
+ new Range<>(20f, 40f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.28f, 0.643f)),
+ new ColorRange(
+ new Range<>(20f, 40f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.414f, 0.561f)),
+ new ColorRange(
+ new Range<>(20f, 40f),
+ new Range<>(0f, 3f),
+ new Range<>(0.343f, 0.584f)),
+
+ // Orange
+ new ColorRange(
+ new Range<>(40f, 60f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.173f, 0.349f)),
+ new ColorRange(
+ new Range<>(40f, 60f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.233f, 0.427f)),
+ new ColorRange(
+ new Range<>(40f, 60f),
+ new Range<>(0f, 0.3f),
+ new Range<>(0.231f, 0.484f)),
+
+ // Yellow 60
+ new ColorRange(
+ new Range<>(60f, 80f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.488f, 0.737f)),
+ new ColorRange(
+ new Range<>(60f, 80f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.673f, 0.837f)),
+
+ // Yellow Green 80
+ new ColorRange(
+ new Range<>(80f, 100f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.469f, 0.61f)),
+
+ // Yellow green 100
+ new ColorRange(
+ new Range<>(100f, 120f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.388f, 0.612f)),
+ new ColorRange(
+ new Range<>(100f, 120f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.424f, 0.541f)),
+
+ // Green
+ new ColorRange(
+ new Range<>(120f, 140f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.375f, 0.52f)),
+ new ColorRange(
+ new Range<>(120f, 140f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.435f, 0.524f)),
+
+ // Green Blue 140
+ new ColorRange(
+ new Range<>(140f, 160f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.496f, 0.641f)),
+
+ // Seafoam
+ new ColorRange(
+ new Range<>(160f, 180f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.496f, 0.567f)),
+
+ // Cyan
+ new ColorRange(
+ new Range<>(180f, 200f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.52f, 0.729f)),
+
+ // Blue
+ new ColorRange(
+ new Range<>(220f, 240f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.396f, 0.571f)),
+ new ColorRange(
+ new Range<>(220f, 240f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.425f, 0.551f)),
+
+ // Blue Purple 240
+ new ColorRange(
+ new Range<>(240f, 260f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.418f, 0.639f)),
+ new ColorRange(
+ new Range<>(220f, 240f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.441f, 0.576f)),
+
+ // Blue Purple 260
+ new ColorRange(
+ new Range<>(260f, 280f),
+ new Range<>(0.3f, 1f), // Bigger range
+ new Range<>(0.461f, 0.553f)),
+
+ // Fuchsia
+ new ColorRange(
+ new Range<>(300f, 320f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.484f, 0.588f)),
+ new ColorRange(
+ new Range<>(300f, 320f),
+ new Range<>(0.3f, 0.7f),
+ new Range<>(0.48f, 0.592f)),
+
+ // Pink
+ new ColorRange(
+ new Range<>(320f, 340f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.466f, 0.629f)),
+
+ // Soft red
+ new ColorRange(
+ new Range<>(340f, 360f),
+ new Range<>(0.7f, 1f),
+ new Range<>(0.437f, 0.596f))
+ };
+
+ /**
+ * Representation of an HSL color range.
+ * <ul>
+ * <li>hsl[0] is Hue [0 .. 360)</li>
+ * <li>hsl[1] is Saturation [0...1]</li>
+ * <li>hsl[2] is Lightness [0...1]</li>
+ * </ul>
+ */
+ static class ColorRange {
+ private Range<Float> mHue;
+ private Range<Float> mSaturation;
+ private Range<Float> mLightness;
+
+ ColorRange(Range<Float> hue, Range<Float> saturation, Range<Float> lightness) {
+ mHue = hue;
+ mSaturation = saturation;
+ mLightness = lightness;
+ }
+
+ boolean containsColor(float h, float s, float l) {
+ if (!mHue.contains(h)) {
+ return false;
+ } else if (!mSaturation.contains(s)) {
+ return false;
+ } else if (!mLightness.contains(l)) {
+ return false;
+ }
+ return true;
+ }
+
+ float[] getCenter() {
+ return new float[] {
+ mHue.getLower() + (mHue.getUpper() - mHue.getLower()) / 2f,
+ mSaturation.getLower() + (mSaturation.getUpper() - mSaturation.getLower()) / 2f,
+ mLightness.getLower() + (mLightness.getUpper() - mLightness.getLower()) / 2f
+ };
+ }
+
+ @Override
+ public String toString() {
+ return String.format("H: %s, S: %s, L %s", mHue, mSaturation, mLightness);
+ }
+ }
+
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
new file mode 100644
index 0000000..bcf516e
--- /dev/null
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -0,0 +1,839 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageInstaller;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.MutableInt;
+
+import com.android.launcher3.AllAppsList;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.InstallShortcutReceiver;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.PackageInstallerCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderIconPreviewVerifier;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.provider.ImportDataTask;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LooperIdleLock;
+import com.android.launcher3.util.ManagedProfileHeuristic;
+import com.android.launcher3.util.MultiHashMap;
+import com.android.launcher3.util.PackageManagerHelper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CancellationException;
+
+/**
+ * Runnable for the thread that loads the contents of the launcher:
+ * - workspace icons
+ * - widgets
+ * - all apps icons
+ * - deep shortcuts within apps
+ */
+public class LoaderTask implements Runnable {
+ private static final boolean DEBUG_LOADERS = false;
+ private static final String TAG = "LoaderTask";
+
+ private final LauncherAppState mApp;
+ private final AllAppsList mBgAllAppsList;
+ private final BgDataModel mBgDataModel;
+
+ private final LoaderResults mResults;
+
+ private final LauncherAppsCompat mLauncherApps;
+ private final UserManagerCompat mUserManager;
+ private final DeepShortcutManager mShortcutManager;
+ private final PackageInstallerCompat mPackageInstaller;
+ private final AppWidgetManagerCompat mAppWidgetManager;
+ private final IconCache mIconCache;
+
+ private boolean mStopped;
+
+ public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
+ LoaderResults results) {
+ mApp = app;
+ mBgAllAppsList = bgAllAppsList;
+ mBgDataModel = dataModel;
+ mResults = results;
+
+ mLauncherApps = LauncherAppsCompat.getInstance(mApp.getContext());
+ mUserManager = UserManagerCompat.getInstance(mApp.getContext());
+ mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext());
+ mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());
+ mAppWidgetManager = AppWidgetManagerCompat.getInstance(mApp.getContext());
+ mIconCache = mApp.getIconCache();
+ }
+
+ private synchronized void waitForIdle() {
+ // Wait until the either we're stopped or the other threads are done.
+ // This way we don't start loading all apps until the workspace has settled
+ // down.
+ LooperIdleLock idleLock = new LooperIdleLock(this, Looper.getMainLooper());
+ // Just in case mFlushingWorkerThread changes but we aren't woken up,
+ // wait no longer than 1sec at a time
+ while (!mStopped && idleLock.awaitLocked(1000));
+ }
+
+ private synchronized void verifyNotStopped() throws CancellationException {
+ if (mStopped) {
+ throw new CancellationException("Loader stopped");
+ }
+ }
+
+ public void run() {
+ synchronized (this) {
+ // Skip fast if we are already stopped.
+ if (mStopped) {
+ return;
+ }
+ }
+
+ try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
+ long now = 0;
+ if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
+ loadWorkspace();
+
+ verifyNotStopped();
+ if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
+ mResults.bindWorkspace();
+
+ // Take a break
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "step 1 completed, wait for idle");
+ now = SystemClock.uptimeMillis();
+ }
+ waitForIdle();
+ if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
+ verifyNotStopped();
+
+ // second step
+ if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
+ loadAllApps();
+
+ if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps");
+ verifyNotStopped();
+ mResults.bindAllApps();
+
+ verifyNotStopped();
+ if (DEBUG_LOADERS) Log.d(TAG, "step 2.3: Update icon cache");
+ updateIconCache();
+
+ // Take a break
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "step 2 completed, wait for idle");
+ now = SystemClock.uptimeMillis();
+ }
+ waitForIdle();
+ if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
+ verifyNotStopped();
+
+ // third step
+ if (DEBUG_LOADERS) Log.d(TAG, "step 3.1: loading deep shortcuts");
+ loadDeepShortcuts();
+
+ verifyNotStopped();
+ if (DEBUG_LOADERS) Log.d(TAG, "step 3.2: bind deep shortcuts");
+ mResults.bindDeepShortcuts();
+
+ // Take a break
+ if (DEBUG_LOADERS) Log.d(TAG, "step 3 completed, wait for idle");
+ waitForIdle();
+ verifyNotStopped();
+
+ // fourth step
+ if (DEBUG_LOADERS) Log.d(TAG, "step 4.1: loading widgets");
+ mBgDataModel.widgetsModel.update(mApp, null);
+
+ verifyNotStopped();
+ if (DEBUG_LOADERS) Log.d(TAG, "step 4.2: Binding widgets");
+ mResults.bindWidgets();
+
+ transaction.commit();
+ } catch (CancellationException e) {
+ // Loader stopped, ignore
+ }
+ }
+
+ public synchronized void stopLocked() {
+ mStopped = true;
+ this.notify();
+ }
+
+ private void loadWorkspace() {
+ if (LauncherAppState.PROFILE_STARTUP) {
+ Trace.beginSection("Loading Workspace");
+ }
+
+ final Context context = mApp.getContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+ final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
+ final boolean isSafeMode = pmHelper.isSafeMode();
+ final boolean isSdCardReady = Utilities.isBootCompleted();
+ final MultiHashMap<UserHandle, String> pendingPackages = new MultiHashMap<>();
+
+ boolean clearDb = false;
+ try {
+ ImportDataTask.performImportIfPossible(context);
+ } catch (Exception e) {
+ // Migration failed. Clear workspace.
+ clearDb = true;
+ }
+
+ if (!clearDb && GridSizeMigrationTask.ENABLED &&
+ !GridSizeMigrationTask.migrateGridIfNeeded(context)) {
+ // Migration failed. Clear workspace.
+ clearDb = true;
+ }
+
+ if (clearDb) {
+ Log.d(TAG, "loadWorkspace: resetting launcher database");
+ LauncherSettings.Settings.call(contentResolver,
+ LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+ }
+
+ Log.d(TAG, "loadWorkspace: loading default favorites");
+ LauncherSettings.Settings.call(contentResolver,
+ LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
+
+ synchronized (mBgDataModel) {
+ mBgDataModel.clear();
+
+ final HashMap<String, Integer> installingPkgs =
+ mPackageInstaller.updateAndGetActiveSessionCache();
+ mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));
+
+ Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
+ final LoaderCursor c = new LoaderCursor(contentResolver.query(
+ LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
+
+ HashMap<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null;
+
+ try {
+ final int appWidgetIdIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.APPWIDGET_ID);
+ final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.APPWIDGET_PROVIDER);
+ final int spanXIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.SPANX);
+ final int spanYIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.SPANY);
+ final int rankIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.RANK);
+ final int optionsIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.OPTIONS);
+
+ final LongSparseArray<UserHandle> allUsers = c.allUsers;
+ final LongSparseArray<Boolean> quietMode = new LongSparseArray<>();
+ final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
+ for (UserHandle user : mUserManager.getUserProfiles()) {
+ long serialNo = mUserManager.getSerialNumberForUser(user);
+ allUsers.put(serialNo, user);
+ quietMode.put(serialNo, mUserManager.isQuietModeEnabled(user));
+
+ boolean userUnlocked = mUserManager.isUserUnlocked(user);
+
+ // We can only query for shortcuts when the user is unlocked.
+ if (userUnlocked) {
+ List<ShortcutInfoCompat> pinnedShortcuts =
+ mShortcutManager.queryForPinnedShortcuts(null, user);
+ if (mShortcutManager.wasLastCallSuccess()) {
+ for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
+ shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
+ shortcut);
+ }
+ } else {
+ // Shortcut manager can fail due to some race condition when the
+ // lock state changes too frequently. For the purpose of the loading
+ // shortcuts, consider the user is still locked.
+ userUnlocked = false;
+ }
+ }
+ unlockedUsers.put(serialNo, userUnlocked);
+ }
+
+ ShortcutInfo info;
+ LauncherAppWidgetInfo appWidgetInfo;
+ Intent intent;
+ String targetPkg;
+
+ FolderIconPreviewVerifier verifier =
+ new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
+ while (!mStopped && c.moveToNext()) {
+ try {
+ if (c.user == null) {
+ // User has been deleted, remove the item.
+ c.markDeleted("User has been deleted");
+ continue;
+ }
+
+ boolean allowMissingTarget = false;
+ switch (c.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ intent = c.parseIntent();
+ if (intent == null) {
+ c.markDeleted("Invalid or null intent");
+ continue;
+ }
+
+ int disabledState = quietMode.get(c.serialNumber) ?
+ ShortcutInfo.FLAG_DISABLED_QUIET_USER : 0;
+ ComponentName cn = intent.getComponent();
+ targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
+
+ if (!Process.myUserHandle().equals(c.user)) {
+ if (c.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+ c.markDeleted("Legacy shortcuts are only allowed for default user");
+ continue;
+ } else if (c.restoreFlag != 0) {
+ // Don't restore items for other profiles.
+ c.markDeleted("Restore from managed profile not supported");
+ continue;
+ }
+ }
+ if (TextUtils.isEmpty(targetPkg) &&
+ c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+ c.markDeleted("Only legacy shortcuts can have null package");
+ continue;
+ }
+
+ // If there is no target package, its an implicit intent
+ // (legacy shortcut) which is always valid
+ boolean validTarget = TextUtils.isEmpty(targetPkg) ||
+ mLauncherApps.isPackageEnabledForProfile(targetPkg, c.user);
+
+ if (cn != null && validTarget) {
+ // If the apk is present and the shortcut points to a specific
+ // component.
+
+ // If the component is already present
+ if (mLauncherApps.isActivityEnabledForProfile(cn, c.user)) {
+ // no special handling necessary for this item
+ c.markRestored();
+ } else {
+ if (c.hasRestoreFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
+ // We allow auto install apps to have their intent
+ // updated after an install.
+ intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
+ if (intent != null) {
+ c.restoreFlag = 0;
+ c.updater().put(
+ LauncherSettings.Favorites.INTENT,
+ intent.toUri(0)).commit();
+ cn = intent.getComponent();
+ } else {
+ c.markDeleted("Unable to find a launch target");
+ continue;
+ }
+ } else {
+ // The app is installed but the component is no
+ // longer available.
+ c.markDeleted("Invalid component removed: " + cn);
+ continue;
+ }
+ }
+ }
+ // else if cn == null => can't infer much, leave it
+ // else if !validPkg => could be restored icon or missing sd-card
+
+ if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
+ // Points to a valid app (superset of cn != null) but the apk
+ // is not available.
+
+ if (c.restoreFlag != 0) {
+ // Package is not yet available but might be
+ // installed later.
+ FileLog.d(TAG, "package not yet restored: " + targetPkg);
+
+ if (c.hasRestoreFlag(ShortcutInfo.FLAG_RESTORE_STARTED)) {
+ // Restore has started once.
+ } else if (installingPkgs.containsKey(targetPkg)) {
+ // App restore has started. Update the flag
+ c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED;
+ c.updater().commit();
+ } else {
+ c.markDeleted("Unrestored app removed: " + targetPkg);
+ continue;
+ }
+ } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
+ // Package is present but not available.
+ disabledState |= ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true;
+ } else if (!isSdCardReady) {
+ // SdCard is not ready yet. Package might get available,
+ // once it is ready.
+ Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+ pendingPackages.addToList(c.user, targetPkg);
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true;
+ } else {
+ // Do not wait for external media load anymore.
+ c.markDeleted("Invalid package removed: " + targetPkg);
+ continue;
+ }
+ }
+
+ if (validTarget) {
+ // The shortcut points to a valid target (either no target
+ // or something which is ready to be used)
+ c.markRestored();
+ }
+
+ boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() &&
+ !verifier.isItemInPreview(c.getInt(rankIndex));
+
+ if (c.restoreFlag != 0) {
+ // Already verified above that user is same as default user
+ info = c.getRestoredItemInfo(intent);
+ } else if (c.itemType ==
+ LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ info = c.getAppShortcutInfo(
+ intent, allowMissingTarget, useLowResIcon);
+ } else if (c.itemType ==
+ LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+
+ ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
+ if (unlockedUsers.get(c.serialNumber)) {
+ ShortcutInfoCompat pinnedShortcut =
+ shortcutKeyToPinnedShortcuts.get(key);
+ if (pinnedShortcut == null) {
+ // The shortcut is no longer valid.
+ c.markDeleted("Pinned shortcut not found");
+ continue;
+ }
+ info = new ShortcutInfo(pinnedShortcut, context);
+ info.iconBitmap = LauncherIcons
+ .createShortcutIcon(pinnedShortcut, context);
+ if (pmHelper.isAppSuspended(
+ pinnedShortcut.getPackage(), info.user)) {
+ info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
+ intent = info.intent;
+ } else {
+ // Create a shortcut info in disabled mode for now.
+ info = c.loadSimpleShortcut();
+ info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
+ }
+ } else { // item type == ITEM_TYPE_SHORTCUT
+ info = c.loadSimpleShortcut();
+
+ // Shortcuts are only available on the primary profile
+ if (!TextUtils.isEmpty(targetPkg)
+ && pmHelper.isAppSuspended(targetPkg, c.user)) {
+ disabledState |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
+
+ // App shortcuts that used to be automatically added to Launcher
+ // didn't always have the correct intent flags set, so do that
+ // here
+ if (intent.getAction() != null &&
+ intent.getCategories() != null &&
+ intent.getAction().equals(Intent.ACTION_MAIN) &&
+ intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+ }
+
+ if (info != null) {
+ c.applyCommonProperties(info);
+
+ info.intent = intent;
+ info.rank = c.getInt(rankIndex);
+ info.spanX = 1;
+ info.spanY = 1;
+ info.isDisabled |= disabledState;
+ if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
+ info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
+ }
+
+ if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+ Integer progress = installingPkgs.get(targetPkg);
+ if (progress != null) {
+ info.setInstallProgress(progress);
+ } else {
+ info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+ }
+ }
+
+ c.checkAndAddItem(info, mBgDataModel);
+ } else {
+ throw new RuntimeException("Unexpected null ShortcutInfo");
+ }
+ break;
+
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
+ c.applyCommonProperties(folderInfo);
+
+ // Do not trim the folder label, as is was set by the user.
+ folderInfo.title = c.getString(c.titleIndex);
+ folderInfo.spanX = 1;
+ folderInfo.spanY = 1;
+ folderInfo.options = c.getInt(optionsIndex);
+
+ // no special handling required for restored folders
+ c.markRestored();
+
+ c.checkAndAddItem(folderInfo, mBgDataModel);
+ break;
+
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+ // Read all Launcher-specific widget details
+ boolean customWidget = c.itemType ==
+ LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
+ int appWidgetId = c.getInt(appWidgetIdIndex);
+ String savedProvider = c.getString(appWidgetProviderIndex);
+
+ final ComponentName component =
+ ComponentName.unflattenFromString(savedProvider);
+
+ final boolean isIdValid = !c.hasRestoreFlag(
+ LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
+ final boolean wasProviderReady = !c.hasRestoreFlag(
+ LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
+
+ if (widgetProvidersMap == null) {
+ widgetProvidersMap = mAppWidgetManager.getAllProvidersMap();
+ }
+ final AppWidgetProviderInfo provider = widgetProvidersMap.get(
+ new ComponentKey(
+ ComponentName.unflattenFromString(savedProvider),
+ c.user));
+
+ final boolean isProviderReady = isValidProvider(provider);
+ if (!isSafeMode && !customWidget &&
+ wasProviderReady && !isProviderReady) {
+ c.markDeleted(
+ "Deleting widget that isn't installed anymore: "
+ + provider);
+ } else {
+ if (isProviderReady) {
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ provider.provider);
+
+ // The provider is available. So the widget is either
+ // available or not available. We do not need to track
+ // any future restore updates.
+ int status = c.restoreFlag &
+ ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+ if (!wasProviderReady) {
+ // If provider was not previously ready, update the
+ // status and UI flag.
+
+ // Id would be valid only if the widget restore broadcast was received.
+ if (isIdValid) {
+ status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+ } else {
+ status &= ~LauncherAppWidgetInfo
+ .FLAG_PROVIDER_NOT_READY;
+ }
+ }
+ appWidgetInfo.restoreStatus = status;
+ } else {
+ Log.v(TAG, "Widget restore pending id=" + c.id
+ + " appWidgetId=" + appWidgetId
+ + " status =" + c.restoreFlag);
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ component);
+ appWidgetInfo.restoreStatus = c.restoreFlag;
+ Integer installProgress = installingPkgs.get(component.getPackageName());
+
+ if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
+ // Restore has started once.
+ } else if (installProgress != null) {
+ // App restore has started. Update the flag
+ appWidgetInfo.restoreStatus |=
+ LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+ } else if (!isSafeMode) {
+ c.markDeleted("Unrestored widget removed: " + component);
+ continue;
+ }
+
+ appWidgetInfo.installProgress =
+ installProgress == null ? 0 : installProgress;
+ }
+ if (appWidgetInfo.hasRestoreFlag(
+ LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+ appWidgetInfo.bindOptions = c.parseIntent();
+ }
+
+ c.applyCommonProperties(appWidgetInfo);
+ appWidgetInfo.spanX = c.getInt(spanXIndex);
+ appWidgetInfo.spanY = c.getInt(spanYIndex);
+ appWidgetInfo.user = c.user;
+
+ if (!c.isOnWorkspaceOrHotseat()) {
+ c.markDeleted("Widget found where container != " +
+ "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
+ continue;
+ }
+
+ if (!customWidget) {
+ String providerName =
+ appWidgetInfo.providerName.flattenToString();
+ if (!providerName.equals(savedProvider) ||
+ (appWidgetInfo.restoreStatus != c.restoreFlag)) {
+ c.updater()
+ .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+ providerName)
+ .put(LauncherSettings.Favorites.RESTORED,
+ appWidgetInfo.restoreStatus)
+ .commit();
+ }
+ }
+
+ if (appWidgetInfo.restoreStatus !=
+ LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ String pkg = appWidgetInfo.providerName.getPackageName();
+ appWidgetInfo.pendingItemInfo = new PackageItemInfo(pkg);
+ appWidgetInfo.pendingItemInfo.user = appWidgetInfo.user;
+ mIconCache.getTitleAndIconForApp(
+ appWidgetInfo.pendingItemInfo, false);
+ }
+
+ c.checkAndAddItem(appWidgetInfo, mBgDataModel);
+ }
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Desktop items loading interrupted", e);
+ }
+ }
+ } finally {
+ Utilities.closeSilently(c);
+ }
+
+ // Break early if we've stopped loading
+ if (mStopped) {
+ mBgDataModel.clear();
+ return;
+ }
+
+ // Remove dead items
+ if (c.commitDeleted()) {
+ // Remove any empty folder
+ ArrayList<Long> deletedFolderIds = (ArrayList<Long>) LauncherSettings.Settings
+ .call(contentResolver,
+ LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
+ .getSerializable(LauncherSettings.Settings.EXTRA_VALUE);
+ for (long folderId : deletedFolderIds) {
+ mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
+ mBgDataModel.folders.remove(folderId);
+ mBgDataModel.itemsIdMap.remove(folderId);
+ }
+
+ // Remove any ghost widgets
+ LauncherSettings.Settings.call(contentResolver,
+ LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
+ }
+
+ // Unpin shortcuts that don't exist on the workspace.
+ HashSet<ShortcutKey> pendingShortcuts =
+ InstallShortcutReceiver.getPendingShortcuts(context);
+ for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
+ MutableInt numTimesPinned = mBgDataModel.pinnedShortcutCounts.get(key);
+ if ((numTimesPinned == null || numTimesPinned.value == 0)
+ && !pendingShortcuts.contains(key)) {
+ // Shortcut is pinned but doesn't exist on the workspace; unpin it.
+ mShortcutManager.unpinShortcut(key);
+ }
+ }
+
+ FolderIconPreviewVerifier verifier =
+ new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
+ // Sort the folder items and make sure all items in the preview are high resolution.
+ for (FolderInfo folder : mBgDataModel.folders) {
+ Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
+ verifier.setFolderInfo(folder);
+
+ int numItemsInPreview = 0;
+ for (ShortcutInfo info : folder.contents) {
+ if (info.usingLowResIcon
+ && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && verifier.isItemInPreview(info.rank)) {
+ mIconCache.getTitleAndIcon(info, false);
+ numItemsInPreview++;
+ }
+
+ if (numItemsInPreview >= FolderIcon.NUM_ITEMS_IN_PREVIEW) {
+ break;
+ }
+ }
+ }
+
+ c.commitRestoredItems();
+ if (!isSdCardReady && !pendingPackages.isEmpty()) {
+ context.registerReceiver(
+ new SdCardAvailableReceiver(mApp, pendingPackages),
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED),
+ null,
+ new Handler(LauncherModel.getWorkerLooper()));
+ }
+
+ // Remove any empty screens
+ ArrayList<Long> unusedScreens = new ArrayList<>(mBgDataModel.workspaceScreens);
+ for (ItemInfo item: mBgDataModel.itemsIdMap) {
+ long screenId = item.screenId;
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ unusedScreens.contains(screenId)) {
+ unusedScreens.remove(screenId);
+ }
+ }
+
+ // If there are any empty screens remove them, and update.
+ if (unusedScreens.size() != 0) {
+ mBgDataModel.workspaceScreens.removeAll(unusedScreens);
+ LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens);
+ }
+ }
+ if (LauncherAppState.PROFILE_STARTUP) {
+ Trace.endSection();
+ }
+ }
+
+ private void updateIconCache() {
+ // Ignore packages which have a promise icon.
+ HashSet<String> packagesToIgnore = new HashSet<>();
+ synchronized (mBgDataModel) {
+ for (ItemInfo info : mBgDataModel.itemsIdMap) {
+ if (info instanceof ShortcutInfo) {
+ ShortcutInfo si = (ShortcutInfo) info;
+ if (si.isPromise() && si.getTargetComponent() != null) {
+ packagesToIgnore.add(si.getTargetComponent().getPackageName());
+ }
+ } else if (info instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;
+ if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
+ packagesToIgnore.add(lawi.providerName.getPackageName());
+ }
+ }
+ }
+ }
+ mIconCache.updateDbIcons(packagesToIgnore);
+ }
+
+ private void loadAllApps() {
+ final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+
+ final List<UserHandle> profiles = mUserManager.getUserProfiles();
+
+ // Clear the list of apps
+ mBgAllAppsList.clear();
+ for (UserHandle user : profiles) {
+ // Query for the set of apps
+ final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+ final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "getActivityList took "
+ + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
+ Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
+ }
+ // Fail if we don't have any apps
+ // TODO: Fix this. Only fail for the current user.
+ if (apps == null || apps.isEmpty()) {
+ return;
+ }
+ boolean quietMode = mUserManager.isQuietModeEnabled(user);
+ // Create the ApplicationInfos
+ for (int i = 0; i < apps.size(); i++) {
+ LauncherActivityInfo app = apps.get(i);
+ // This builds the icon bitmaps.
+ mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
+ }
+
+ ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
+ }
+
+ if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
+ // get all active sessions and add them to the all apps list
+ for (PackageInstaller.SessionInfo info :
+ mPackageInstaller.getAllVerifiedSessions()) {
+ mBgAllAppsList.addPromiseApp(mApp.getContext(),
+ PackageInstallerCompat.PackageInstallInfo.fromInstallingState(info));
+ }
+ }
+
+ mBgAllAppsList.added = new ArrayList<>();
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "All apps loaded in in "
+ + (SystemClock.uptimeMillis() - loadTime) + "ms");
+ }
+ }
+
+ private void loadDeepShortcuts() {
+ mBgDataModel.deepShortcutMap.clear();
+ mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission();
+ if (mBgDataModel.hasShortcutHostPermission) {
+ for (UserHandle user : mUserManager.getUserProfiles()) {
+ if (mUserManager.isUserUnlocked(user)) {
+ List<ShortcutInfoCompat> shortcuts =
+ mShortcutManager.queryForAllShortcuts(user);
+ mBgDataModel.updateDeepShortcutMap(null, user, shortcuts);
+ }
+ }
+ }
+ }
+
+ public static boolean isValidProvider(AppWidgetProviderInfo provider) {
+ return (provider != null) && (provider.provider != null)
+ && (provider.provider.getPackageName() != null);
+ }
+}
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 051c033..b83c9b9 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -205,6 +205,7 @@
collapseFooter.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ ((ViewGroup) getParent()).findViewById(R.id.divider).setVisibility(GONE);
((ViewGroup) getParent()).removeView(NotificationFooterLayout.this);
}
});
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 152886e..fa4caab 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -278,6 +278,9 @@
int footerHeight = notificationFooterHasIcons ?
res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0;
item.findViewById(R.id.footer).getLayoutParams().height = footerHeight;
+ if (notificationFooterHasIcons) {
+ mNotificationItemView.findViewById(R.id.divider).setVisibility(VISIBLE);
+ }
int roundedCorners = ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS;
if (shouldUnroundTopCorners) {