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
This commit is contained in:
parent
22b92df30f
commit
91498abf75
|
@ -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 final Handler sHandler = new Handler(LauncherModel.getWorkerLooper()) {
|
||||
|
||||
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();
|
||||
@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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) { }
|
||||
|
|
Loading…
Reference in New Issue