Removing static state management from the install shortcut queue

Change-Id: I0b74a843b2081ee314e0840d5ea8ab8ddabde32b
This commit is contained in:
Sunny Goyal
2020-08-12 14:37:15 -07:00
parent 73f0c3698f
commit 60e68c91e9
8 changed files with 113 additions and 65 deletions
+14 -10
View File
@@ -24,7 +24,6 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.InstallShortcutReceiver.FLAG_DRAG_AND_DROP;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
@@ -43,6 +42,9 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKG
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP;
import static com.android.launcher3.logging.StatsLogManager.containerTypeToAtomState;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
@@ -120,6 +122,7 @@ import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.ModelUtils;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.AppInfo;
@@ -912,8 +915,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
getUserEventDispatcher().startSession();
// Process any items that were added while Launcher was away.
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
ItemInstallQueue.INSTANCE.get(this)
.resumeModelPush(FLAG_ACTIVITY_PAUSED);
// Refresh shortcuts if the permission changed.
mModel.validateModelDataOnResume();
@@ -1007,7 +1010,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
if (state == SPRING_LOADED) {
// Prevent any Un/InstallShortcutReceivers from updating the db while we are
// not on homescreen
InstallShortcutReceiver.enableInstallQueue(FLAG_DRAG_AND_DROP);
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_DRAG_AND_DROP);
getRotationHelper().setCurrentStateRequest(REQUEST_LOCK);
mWorkspace.showPageIndicatorAtCurrentScroll();
@@ -1032,7 +1035,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
if (state == NORMAL) {
// Re-enable any Un/InstallShortcutReceiver and now process any queued items
InstallShortcutReceiver.disableAndFlushInstallQueue(FLAG_DRAG_AND_DROP, this);
ItemInstallQueue.INSTANCE.get(this)
.resumeModelPush(FLAG_DRAG_AND_DROP);
// Clear any rotation locks when going to normal state
getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
@@ -1066,7 +1070,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
@Override
protected void onPause() {
// Ensure that items added to Launcher are queued until Launcher returns
InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED);
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
super.onPause();
mDragController.cancelDrag();
@@ -2421,8 +2425,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
mPendingActivityResult = null;
}
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_LOADER_RUNNING, this);
ItemInstallQueue.INSTANCE.get(this)
.resumeModelPush(FLAG_LOADER_RUNNING);
// When undoing the removal of the last item on a page, return to that page.
// Since we are just resetting the current page without user interaction,
@@ -2449,8 +2453,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
.setDuration(ItemInstallQueue.NEW_SHORTCUT_BOUNCE_DURATION);
bounceAnim.setStartDelay(i * ItemInstallQueue.NEW_SHORTCUT_STAGGER_DELAY);
bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
return bounceAnim;
}
+3 -1
View File
@@ -43,6 +43,7 @@ import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.CacheDataUpdatedTask;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.LoaderResults;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDelegate;
@@ -330,7 +331,8 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
*/
public boolean startLoader() {
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
ItemInstallQueue.INSTANCE.get(mApp.getContext())
.pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
synchronized (mLock) {
// Don't bother to start the thread if we know it's not going to do anything
final Callbacks[] callbacksList = getCallbacks();
@@ -25,6 +25,7 @@ import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.text.TextUtils;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.pm.InstallSessionHelper;
/**
@@ -59,7 +60,8 @@ public class SessionCommitReceiver extends BroadcastReceiver {
return;
}
InstallShortcutReceiver.queueApplication(info.getAppPackageName(), user, context);
ItemInstallQueue.INSTANCE.get(context)
.queueItem(info.getAppPackageName(), user);
}
public static boolean isEnabled(Context context) {
@@ -43,13 +43,13 @@ import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -249,7 +249,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
*/
public void onPlaceAutomaticallyClick(View v) {
if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
InstallShortcutReceiver.queueShortcut(mRequest.getShortcutInfo(), this);
ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo());
logCommand(Action.Command.CONFIRM);
mRequest.accept();
finish();
@@ -270,7 +270,8 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
}
private void acceptWidget(int widgetId) {
InstallShortcutReceiver.queueWidget(mRequest.getAppWidgetProviderInfo(this), widgetId, this);
ItemInstallQueue.INSTANCE.get(this)
.queueItem(mRequest.getAppWidgetProviderInfo(this), widgetId);
mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
mRequest.accept(mWidgetOptions);
logCommand(Action.Command.CONFIRM);
@@ -31,7 +31,6 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace;
@@ -298,7 +297,7 @@ public class BgDataModel {
.filter(wi -> wi.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
.map(ShortcutKey::fromItemInfo),
// Pending shortcuts
InstallShortcutReceiver.getPendingShortcuts(context)
ItemInstallQueue.INSTANCE.get(context).getPendingShortcuts()
.stream().filter(si -> si.user.equals(user)))
.collect(groupingBy(ShortcutKey::getPackageName,
mapping(ShortcutKey::getId, Collectors.toSet())));
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.launcher3;
package com.android.launcher3.model;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
@@ -42,13 +42,19 @@ import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import org.json.JSONException;
@@ -63,16 +69,15 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class InstallShortcutReceiver {
/**
* Class to maintain a queue of pending items to be added to the workspace.
*/
public class ItemInstallQueue {
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;
// Determines whether to defer installing shortcuts immediately until
// processAllPendingInstalls() is called.
private static int sInstallQueueDisabledFlags = 0;
private static final String TAG = "InstallShortcutReceiver";
private static final boolean DBG = false;
@@ -82,10 +87,23 @@ public class InstallShortcutReceiver {
public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
public static MainThreadInitializedObject<ItemInstallQueue> INSTANCE =
new MainThreadInitializedObject<>(ItemInstallQueue::new);
private final Context mContext;
// Determines whether to defer installing shortcuts immediately until
// processAllPendingInstalls() is called.
private int mInstallQueueDisabledFlags = 0;
private ItemInstallQueue(Context context) {
mContext = context;
}
@WorkerThread
private static void addToQueue(Context context, PendingInstallShortcutInfo info) {
String encoded = info.encodeToString(context);
SharedPreferences prefs = Utilities.getPrefs(context);
private void addToQueue(PendingInstallShortcutInfo info) {
String encoded = info.encodeToString(mContext);
SharedPreferences prefs = Utilities.getPrefs(mContext);
Set<String> strings = prefs.getStringSet(APPS_PENDING_INSTALL, null);
strings = (strings != null) ? new HashSet<>(strings) : new HashSet<>(1);
strings.add(encoded);
@@ -93,14 +111,15 @@ public class InstallShortcutReceiver {
}
@WorkerThread
private static void flushQueueInBackground(Context context) {
if (Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null) {
private void flushQueueInBackground() {
Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
if (launcher == null) {
// Launcher not loaded
return;
}
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
SharedPreferences prefs = Utilities.getPrefs(context);
SharedPreferences prefs = Utilities.getPrefs(mContext);
Set<String> strings = prefs.getStringSet(APPS_PENDING_INSTALL, null);
if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings);
if (strings == null) {
@@ -108,29 +127,31 @@ public class InstallShortcutReceiver {
}
for (String encoded : strings) {
PendingInstallShortcutInfo info = decode(encoded, context);
PendingInstallShortcutInfo info = decode(encoded, mContext);
if (info == null) {
continue;
}
// Generate a shortcut info to add into the model
installQueue.add(info.getItemInfo(context));
installQueue.add(info.getItemInfo(mContext));
}
prefs.edit().remove(APPS_PENDING_INSTALL).apply();
if (!installQueue.isEmpty()) {
LauncherAppState.getInstance(context).getModel()
.addAndBindAddedWorkspaceItems(installQueue);
launcher.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
public static void removeFromInstallQueue(Context context, HashSet<String> packageNames,
UserHandle user) {
/**
* Removes previously added items from the queue.
*/
@WorkerThread
public void removeFromInstallQueue(HashSet<String> packageNames, UserHandle user) {
if (packageNames.isEmpty()) {
return;
}
Preconditions.assertWorkerThread();
SharedPreferences sp = Utilities.getPrefs(context);
SharedPreferences sp = Utilities.getPrefs(mContext);
Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null);
if (DBG) {
Log.d(TAG, "APPS_PENDING_INSTALL: " + strings
@@ -144,7 +165,7 @@ public class InstallShortcutReceiver {
while (newStringsIter.hasNext()) {
String encoded = newStringsIter.next();
try {
Decoder decoder = new Decoder(encoded, context);
Decoder decoder = new Decoder(encoded, mContext);
if (packageNames.contains(getIntentPackage(decoder.intent))
&& user.equals(decoder.user)) {
newStringsIter.remove();
@@ -157,30 +178,42 @@ public class InstallShortcutReceiver {
sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
}
public static void queueShortcut(ShortcutInfo info, Context context) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info), context);
/**
* Adds an item to the install queue
*/
public void queueItem(ShortcutInfo info) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info));
}
public static void queueWidget(AppWidgetProviderInfo info, int widgetId, Context context) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId), context);
/**
* Adds an item to the install queue
*/
public void queueItem(AppWidgetProviderInfo info, int widgetId) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId));
}
public static void queueApplication(
String packageName, UserHandle userHandle, Context context) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle), context);
/**
* Adds an item to the install queue
*/
public void queueItem(String packageName, UserHandle userHandle) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle));
}
public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
/**
* Returns all pending shorts in the queue
*/
@WorkerThread
public HashSet<ShortcutKey> getPendingShortcuts() {
HashSet<ShortcutKey> result = new HashSet<>();
Set<String> strings = Utilities.getPrefs(context).getStringSet(APPS_PENDING_INSTALL, null);
Set<String> strings = Utilities.getPrefs(mContext).getStringSet(APPS_PENDING_INSTALL, null);
if (strings == null || ((Collection) strings).isEmpty()) {
return result;
}
for (String encoded : strings) {
try {
Decoder decoder = new Decoder(encoded, context);
Decoder decoder = new Decoder(encoded, mContext);
if (decoder.optInt(Favorites.ITEM_TYPE, -1) == ITEM_TYPE_DEEP_SHORTCUT) {
result.add(ShortcutKey.fromIntent(decoder.intent, decoder.user));
}
@@ -191,28 +224,35 @@ public class InstallShortcutReceiver {
return result;
}
private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
private void queuePendingShortcutInfo(PendingInstallShortcutInfo info) {
// Queue the item up for adding if launcher has not loaded properly yet
MODEL_EXECUTOR.post(() -> addToQueue(context, info));
flushInstallQueue(context);
MODEL_EXECUTOR.post(() -> addToQueue(info));
flushInstallQueue();
}
public static void enableInstallQueue(int flag) {
sInstallQueueDisabledFlags |= flag;
}
public static void disableAndFlushInstallQueue(int flag, Context context) {
sInstallQueueDisabledFlags &= ~flag;
flushInstallQueue(context);
/**
* Pauses the push-to-model flow until unpaused. All items are held in the queue and
* not added to the model.
*/
public void pauseModelPush(int flag) {
mInstallQueueDisabledFlags |= flag;
}
static void flushInstallQueue(Context context) {
if (sInstallQueueDisabledFlags != 0) {
/**
* Adds all the queue items to the model if the use is completely resumed.
*/
public void resumeModelPush(int flag) {
mInstallQueueDisabledFlags &= ~flag;
flushInstallQueue();
}
private void flushInstallQueue() {
if (mInstallQueueDisabledFlags != 0) {
return;
}
MODEL_EXECUTOR.post(() -> flushQueueInBackground(context));
MODEL_EXECUTOR.post(this::flushQueueInBackground);
}
private static class PendingInstallShortcutInfo extends ItemInfo {
final Intent intent;
@@ -28,7 +28,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.config.FeatureFlags;
@@ -320,7 +319,8 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
ItemInstallQueue.INSTANCE.get(context)
.removeFromInstallQueue(removedPackages, mUser);
}
if (mOp == OP_ADD) {
@@ -32,11 +32,11 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.SessionCommitReceiver;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LooperExecutor;
@@ -213,8 +213,8 @@ public class InstallSessionHelper {
&& !mPromiseIconIds.contains(sessionInfo.getSessionId())
&& new PackageManagerHelper(mAppContext).getApplicationInfo(
sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) {
InstallShortcutReceiver.queueApplication(
sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), mAppContext);
ItemInstallQueue.INSTANCE.get(mAppContext)
.queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
mPromiseIconIds.add(sessionInfo.getSessionId());
updatePromiseIconPrefs();