Fixing some Launcher crashes because of using old model data even
after launcher has reloaded
Bug: 126289691
Bug: 124288578
Change-Id: Id7fb29716241a13f4e03ee0fc0e879523de4f878
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d65fe76..d820448 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -257,7 +257,7 @@
private RotationHelper mRotationHelper;
- private final Handler mHandler = new Handler();
+ final Handler mHandler = new Handler();
private final Runnable mHandleDeferredResume = this::handleDeferredResume;
@Override
@@ -1748,6 +1748,8 @@
setWorkspaceLoading(true);
// Clear the workspace because it's going to be rebound
+ mDragController.cancelDrag();
+
mWorkspace.clearDropTargets();
mWorkspace.removeAllWorkspaceScreens();
mAppWidgetHost.clearViews();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5ab6eea..b1664f1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -34,6 +34,7 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.AddWorkspaceItemsTask;
@@ -210,20 +211,20 @@
final int itemId, final ItemInfo item, StackTraceElement[] stackTrace) {
ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null && item != modelItem) {
- // check all the data is consistent
- if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {
- ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;
- ShortcutInfo shortcut = (ShortcutInfo) item;
- if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&
- modelShortcut.intent.filterEquals(shortcut.intent) &&
- modelShortcut.id == shortcut.id &&
- modelShortcut.itemType == shortcut.itemType &&
- modelShortcut.container == shortcut.container &&
- modelShortcut.screenId == shortcut.screenId &&
- modelShortcut.cellX == shortcut.cellX &&
- modelShortcut.cellY == shortcut.cellY &&
- modelShortcut.spanX == shortcut.spanX &&
- modelShortcut.spanY == shortcut.spanY) {
+ // If it is a release build on a release device, check all the data is consistent as
+ // we don't want to crash non-dev users.
+ if (!Utilities.IS_DEBUG_DEVICE && !FeatureFlags.IS_DOGFOOD_BUILD &&
+ modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {
+ if (modelItem.title.toString().equals(item.title.toString()) &&
+ modelItem.getIntent().filterEquals(item.getIntent()) &&
+ modelItem.id == item.id &&
+ modelItem.itemType == item.itemType &&
+ modelItem.container == item.container &&
+ modelItem.screenId == item.screenId &&
+ modelItem.cellX == item.cellX &&
+ modelItem.cellY == item.cellY &&
+ modelItem.spanX == item.spanX &&
+ modelItem.spanY == item.spanY) {
// For all intents and purposes, this is the same object
return;
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 119058d..f6b54f2 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -248,6 +248,22 @@
return;
}
+ if (delay > 0) {
+ // Create the animation after the delay as some properties can change between preparing
+ // the animation and running the animation.
+ int startChangeId = mConfig.mChangeId;
+ mUiHandler.postDelayed(() -> {
+ if (mConfig.mChangeId == startChangeId) {
+ goToStateAnimated(state, fromState, onCompleteRunnable);
+ }
+ }, delay);
+ } else {
+ goToStateAnimated(state, fromState, onCompleteRunnable);
+ }
+ }
+
+ private void goToStateAnimated(LauncherState state, LauncherState fromState,
+ Runnable onCompleteRunnable) {
// Since state NORMAL can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
mConfig.duration = state == NORMAL ? fromState.transitionDuration : state.transitionDuration;
@@ -256,12 +272,7 @@
prepareForAtomicAnimation(fromState, state, builder);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(
state, builder, onCompleteRunnable);
- Runnable runnable = new StartAnimRunnable(animation);
- if (delay > 0) {
- mUiHandler.postDelayed(runnable, delay);
- } else {
- mUiHandler.post(runnable);
- }
+ mUiHandler.post(new StartAnimRunnable(animation));
}
/**
@@ -533,6 +544,8 @@
private AnimatorSet mCurrentAnimation;
private LauncherState mTargetState;
+ // Id to keep track of config changes, to tie an animation with the corresponding request
+ private int mChangeId = 0;
/**
* Cancels the current animation and resets config variables.
@@ -554,6 +567,7 @@
mCurrentAnimation = null;
playbackController = null;
+ mChangeId ++;
}
public PropertySetter getPropertySetter(AnimatorSetBuilder builder) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7f5ca42..7eee8af 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -44,6 +44,7 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.AttributeSet;
@@ -521,6 +522,9 @@
mScreenOrder.clear();
mWorkspaceScreens.clear();
+ // Remove any deferred refresh callbacks
+ mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
+
// Ensure that the first page is always present
bindAndInitFirstWorkspaceScreen(qsb);
@@ -3348,13 +3352,15 @@
LauncherAppWidgetHost host) {
mInfos = infos;
mHost = host;
- mHandler = new Handler();
+ mHandler = mLauncher.mHandler;
mRefreshPending = true;
mHost.addProviderChangeListener(this);
// Force refresh after 10 seconds, if we don't get the provider changed event.
// This could happen when the provider is no longer available in the app.
- mHandler.postDelayed(this, 10000);
+ Message msg = Message.obtain(mHandler, this);
+ msg.obj = DeferredWidgetRefresh.class;
+ mHandler.sendMessageDelayed(msg, 10000);
}
@Override