diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2017-10-05 15:57:40 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2017-10-06 11:33:43 -0700 |
commit | 91498abf7552f15624283366be86f91304ad92a2 (patch) | |
tree | 13b54a20cde6998dfc6f893cb3531e8c4c43586b | |
parent | 22b92df30f5a1ec319180cb705175e7563727a36 (diff) | |
download | android_packages_apps_Trebuchet-91498abf7552f15624283366be86f91304ad92a2.tar.gz android_packages_apps_Trebuchet-91498abf7552f15624283366be86f91304ad92a2.tar.bz2 android_packages_apps_Trebuchet-91498abf7552f15624283366be86f91304ad92a2.zip |
Moving install queue updates to worker thread.
This avoids acquiring a lock for upating the sharedPrefs during onResume
as all the logic runs on a single thread.
Bug: 67305604
Change-Id: I1bbea382da9fafb403b4e9508f393f78db28478d
4 files changed, 96 insertions, 112 deletions
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 0370777d1..df1eec661 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -27,7 +27,9 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.os.Parcelable; import android.os.Process; import android.os.UserHandle; @@ -61,6 +63,9 @@ import java.util.Set; public class InstallShortcutReceiver extends BroadcastReceiver { + private static final int MSG_ADD_TO_QUEUE = 1; + private static final int MSG_FLUSH_QUEUE = 2; + public static final int FLAG_ACTIVITY_PAUSED = 1; public static final int FLAG_LOADER_RUNNING = 2; public static final int FLAG_DRAG_AND_DROP = 4; @@ -93,73 +98,98 @@ public class InstallShortcutReceiver extends BroadcastReceiver { public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450; public static final int NEW_SHORTCUT_STAGGER_DELAY = 85; - private static final Object sLock = new Object(); - - private static void addToInstallQueue( - SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) { - synchronized(sLock) { - String encoded = info.encodeToString(); - if (encoded != null) { - Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null); - strings = (strings != null) ? new HashSet<>(strings) : new HashSet<String>(1); - strings.add(encoded); - sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply(); + private static final Handler sHandler = new Handler(LauncherModel.getWorkerLooper()) { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ADD_TO_QUEUE: { + Pair<Context, PendingInstallShortcutInfo> pair = + (Pair<Context, PendingInstallShortcutInfo>) msg.obj; + String encoded = pair.second.encodeToString(); + SharedPreferences prefs = Utilities.getPrefs(pair.first); + Set<String> strings = prefs.getStringSet(APPS_PENDING_INSTALL, null); + strings = (strings != null) ? new HashSet<>(strings) : new HashSet<String>(1); + strings.add(encoded); + prefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply(); + return; + } + case MSG_FLUSH_QUEUE: { + Context context = (Context) msg.obj; + LauncherModel model = LauncherAppState.getInstance(context).getModel(); + if (model.getCallback() == null) { + // Launcher not loaded + return; + } + + ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>(); + SharedPreferences prefs = Utilities.getPrefs(context); + Set<String> strings = prefs.getStringSet(APPS_PENDING_INSTALL, null); + if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings); + if (strings == null) { + return; + } + + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + for (String encoded : strings) { + PendingInstallShortcutInfo info = decode(encoded, context); + if (info == null) { + continue; + } + + String pkg = getIntentPackage(info.launchIntent); + if (!TextUtils.isEmpty(pkg) + && !launcherApps.isPackageEnabledForProfile(pkg, info.user)) { + if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: " + + info.launchIntent); + continue; + } + + // Generate a shortcut info to add into the model + installQueue.add(info.getItemInfo()); + } + prefs.edit().remove(APPS_PENDING_INSTALL).apply(); + if (!installQueue.isEmpty()) { + model.addAndBindAddedWorkspaceItems(installQueue); + } + return; + } } } - } + }; public static void removeFromInstallQueue(Context context, HashSet<String> packageNames, UserHandle user) { if (packageNames.isEmpty()) { return; } + Preconditions.assertWorkerThread(); + SharedPreferences sp = Utilities.getPrefs(context); - synchronized(sLock) { - Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null); - if (DBG) { - Log.d(TAG, "APPS_PENDING_INSTALL: " + strings - + ", removing packages: " + packageNames); - } - if (Utilities.isEmpty(strings)) { - return; - } - Set<String> newStrings = new HashSet<>(strings); - Iterator<String> newStringsIter = newStrings.iterator(); - while (newStringsIter.hasNext()) { - String encoded = newStringsIter.next(); - try { - Decoder decoder = new Decoder(encoded, context); - if (packageNames.contains(getIntentPackage(decoder.launcherIntent)) && - user.equals(decoder.user)) { - newStringsIter.remove(); - } - } catch (JSONException | URISyntaxException e) { - Log.d(TAG, "Exception reading shortcut to add: " + e); - newStringsIter.remove(); - } - } - sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply(); + Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null); + if (DBG) { + Log.d(TAG, "APPS_PENDING_INSTALL: " + strings + + ", removing packages: " + packageNames); } - } - - private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(Context context) { - SharedPreferences sharedPrefs = Utilities.getPrefs(context); - synchronized(sLock) { - ArrayList<PendingInstallShortcutInfo> infos = new ArrayList<>(); - Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null); - if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings); - if (strings == null) { - return infos; - } - for (String encoded : strings) { - PendingInstallShortcutInfo info = decode(encoded, context); - if (info != null) { - infos.add(info); + if (Utilities.isEmpty(strings)) { + return; + } + Set<String> newStrings = new HashSet<>(strings); + Iterator<String> newStringsIter = newStrings.iterator(); + while (newStringsIter.hasNext()) { + String encoded = newStringsIter.next(); + try { + Decoder decoder = new Decoder(encoded, context); + if (packageNames.contains(getIntentPackage(decoder.launcherIntent)) && + user.equals(decoder.user)) { + newStringsIter.remove(); } + } catch (JSONException | URISyntaxException e) { + Log.d(TAG, "Exception reading shortcut to add: " + e); + newStringsIter.remove(); } - sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).apply(); - return infos; } + sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply(); } public void onReceive(Context context, Intent data) { @@ -256,7 +286,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) { // Queue the item up for adding if launcher has not loaded properly yet - addToInstallQueue(Utilities.getPrefs(context), info); + Message.obtain(sHandler, MSG_ADD_TO_QUEUE, Pair.create(context, info)).sendToTarget(); flushInstallQueue(context); } @@ -269,17 +299,10 @@ public class InstallShortcutReceiver extends BroadcastReceiver { } static void flushInstallQueue(Context context) { - LauncherModel model = LauncherAppState.getInstance(context).getModel(); - boolean launcherNotLoaded = model.getCallback() == null; - if (sInstallQueueDisabledFlags != 0 || launcherNotLoaded) { + if (sInstallQueueDisabledFlags != 0) { return; } - - ArrayList<PendingInstallShortcutInfo> items = getAndClearInstallQueue(context); - if (!items.isEmpty()) { - model.addAndBindAddedWorkspaceItems( - new LazyShortcutsProvider(context.getApplicationContext(), items)); - } + Message.obtain(sHandler, MSG_FLUSH_QUEUE, context.getApplicationContext()).sendToTarget(); } /** @@ -601,42 +624,6 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return new PendingInstallShortcutInfo(info, original.mContext); } - private static class LazyShortcutsProvider extends Provider<List<Pair<ItemInfo, Object>>> { - - private final Context mContext; - private final ArrayList<PendingInstallShortcutInfo> mPendingItems; - - public LazyShortcutsProvider(Context context, ArrayList<PendingInstallShortcutInfo> items) { - mContext = context; - mPendingItems = items; - } - - /** - * This must be called on the background thread as this requires multiple calls to - * packageManager and icon cache. - */ - @Override - public ArrayList<Pair<ItemInfo, Object>> get() { - Preconditions.assertNonUiThread(); - ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>(); - LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); - for (PendingInstallShortcutInfo pendingInfo : mPendingItems) { - // If the intent specifies a package, make sure the package exists - String packageName = getIntentPackage(pendingInfo.launchIntent); - if (!TextUtils.isEmpty(packageName) && !launcherApps.isPackageEnabledForProfile( - packageName, pendingInfo.user)) { - if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: " - + pendingInfo.launchIntent); - continue; - } - - // Generate a shortcut info to add into the model - installQueue.add(pendingInfo.getItemInfo()); - } - return installQueue; - } - } - private static ShortcutInfo createShortcutInfo(Intent data, LauncherAppState app) { Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 74a5bac99..3e2236682 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -192,9 +192,8 @@ public class LauncherModel extends BroadcastReceiver /** * Adds the provided items to the workspace. */ - public void addAndBindAddedWorkspaceItems( - Provider<List<Pair<ItemInfo, Object>>> appsProvider) { - enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider)); + public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) { + enqueueModelUpdateTask(new AddWorkspaceItemsTask(itemList)); } public ModelWriter getWriter(boolean hasVerticalHotseat) { diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 42926fa3e..a33a039c0 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -38,7 +38,6 @@ import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.ManagedProfileHeuristic.UserFolderInfo; -import com.android.launcher3.util.Provider; import java.util.ArrayList; import java.util.List; @@ -47,19 +46,18 @@ import java.util.List; */ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { - private final Provider<List<Pair<ItemInfo, Object>>> mAppsProvider; + private final List<Pair<ItemInfo, Object>> mItemList; /** - * @param appsProvider items to add on the workspace + * @param itemList items to add on the workspace */ - public AddWorkspaceItemsTask(Provider<List<Pair<ItemInfo, Object>>> appsProvider) { - mAppsProvider = appsProvider; + public AddWorkspaceItemsTask(List<Pair<ItemInfo, Object>> itemList) { + mItemList = itemList; } @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - List<Pair<ItemInfo, Object>> workspaceApps = mAppsProvider.get(); - if (workspaceApps.isEmpty()) { + if (mItemList.isEmpty()) { return; } Context context = app.getContext(); @@ -75,7 +73,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { synchronized(dataModel) { List<ItemInfo> filteredItems = new ArrayList<>(); - for (Pair<ItemInfo, Object> entry : workspaceApps) { + for (Pair<ItemInfo, Object> entry : mItemList) { ItemInfo item = entry.first; if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java index 82f34e43d..a486cebc2 100644 --- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java +++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java @@ -55,7 +55,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { for (ItemInfo item : items) { list.add(Pair.create(item, null)); } - return new AddWorkspaceItemsTask(Provider.of(list)) { + return new AddWorkspaceItemsTask(list) { @Override protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { } |