Add TaskbarControllers#runAfterInit()
And use it in TaskbarModelCallbacks#commitItemsToUI(), which in rare cases can run during init() before other controllers (namely TaskbarStashController) have been initialized.
Test: call commitItemsToUI() in TaskbarModelCallbacks#init(), ensure no crash
Fixes: 204847702
Change-Id: Ib9df3ea91d41c76ad1d3392e43b444b8b4a91374
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index a7c5d4d..e19b750 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -19,6 +19,9 @@
import com.android.systemui.shared.rotation.RotationButtonController;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Hosts various taskbar controllers to facilitate passing between one another.
*/
@@ -43,6 +46,9 @@
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
+ private boolean mAreAllControllersInitialized;
+ private final List<Runnable> mPostInitCallbacks = new ArrayList<>();
+
public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
TaskbarDragController taskbarDragController,
TaskbarNavButtonController navButtonController,
@@ -81,6 +87,8 @@
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarSharedState sharedState) {
+ mAreAllControllersInitialized = false;
+
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
rotationButtonController.init();
@@ -93,6 +101,12 @@
taskbarStashController.init(this, sharedState);
taskbarEduController.init(this);
taskbarPopupController.init(this);
+
+ mAreAllControllersInitialized = true;
+ for (Runnable postInitCallback : mPostInitCallbacks) {
+ postInitCallback.run();
+ }
+ mPostInitCallbacks.clear();
}
/**
@@ -110,4 +124,17 @@
taskbarAutohideSuspendController.onDestroy();
taskbarPopupController.onDestroy();
}
+
+ /**
+ * If all controllers are already initialized, runs the given callback immediately. Otherwise,
+ * queues it to run after calling init() on all controllers. This should likely be used in any
+ * case where one controller is telling another controller to do something inside init().
+ */
+ public void runAfterInit(Runnable callback) {
+ if (mAreAllControllersInitialized) {
+ callback.run();
+ } else {
+ mPostInitCallbacks.add(callback);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 6dcfe56..37a9b5e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -184,9 +184,12 @@
}
mContainer.updateHotseatItems(hotseatItemInfos);
- mControllers.taskbarStashController.updateStateForFlag(
- TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, isHotseatEmpty);
- mControllers.taskbarStashController.applyState();
+ final boolean finalIsHotseatEmpty = isHotseatEmpty;
+ mControllers.runAfterInit(() -> {
+ mControllers.taskbarStashController.updateStateForFlag(
+ TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty);
+ mControllers.taskbarStashController.applyState();
+ });
}
@Override