From 60180b049eae9d23658456048d5af108f9a47271 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 7 Feb 2018 12:56:30 -0800 Subject: [PATCH] Deferring all app updates until the pending executor is complete. We were only deferring full apps binds and not partial updates which could cause the model to go out of sync with Launcher. Bug: 72051234 Change-Id: I20db0e86aadd1e6a518237026f6dfb03e469eb87 --- src/com/android/launcher3/Launcher.java | 39 +++-------- .../allapps/AllAppsContainerView.java | 69 ++++--------------- .../launcher3/allapps/AllAppsStore.java | 44 +++++++++++- 3 files changed, 68 insertions(+), 84 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5a1143fc08..4d820bc0bc 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -150,7 +150,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.Executor; /** * Default launcher application. @@ -1166,7 +1165,7 @@ public class Launcher extends BaseActivity public void updateIconBadges(final Set updatedBadges) { mWorkspace.updateIconBadges(updatedBadges); - mAppsView.updateIconBadges(updatedBadges); + mAppsView.getAppsStore().updateIconBadges(updatedBadges); PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this); if (popup != null) { @@ -2527,6 +2526,11 @@ public class Launcher extends BaseActivity mPendingExecutor.markCompleted(); } mPendingExecutor = executor; + if (!isInState(ALL_APPS)) { + mAppsView.getAppsStore().setDeferUpdates(true); + mPendingExecutor.execute(() -> mAppsView.getAppsStore().setDeferUpdates(false)); + } + executor.attachTo(this); } @@ -2588,29 +2592,13 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. */ public void bindAllApplications(ArrayList apps) { - if (mAppsView != null) { - Executor pendingExecutor = getPendingExecutor(); - if (pendingExecutor != null && !isInState(ALL_APPS)) { - // Wait until the fade in animation has finished before setting all apps list. - pendingExecutor.execute(() -> bindAllApplications(apps)); - return; - } + mAppsView.getAppsStore().setApps(apps); - mAppsView.setApps(apps); - } if (mLauncherCallbacks != null) { mLauncherCallbacks.bindAllApplications(apps); } } - /** - * Returns an Executor that will run after the launcher is first drawn (including after the - * initial fade in animation). Returns null if the first draw has already occurred. - */ - public @Nullable Executor getPendingExecutor() { - return mPendingExecutor != null && mPendingExecutor.canQueue() ? mPendingExecutor : null; - } - /** * Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary * because LauncherModel's map is updated in the background, while Launcher runs on the UI. @@ -2627,16 +2615,12 @@ public class Launcher extends BaseActivity */ @Override public void bindAppsAddedOrUpdated(ArrayList apps) { - if (mAppsView != null) { - mAppsView.addOrUpdateApps(apps); - } + mAppsView.getAppsStore().addOrUpdateApps(apps); } @Override public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { - if (mAppsView != null) { - mAppsView.updatePromiseAppProgress(app); - } + mAppsView.getAppsStore().updatePromiseAppProgress(app); } @Override @@ -2682,10 +2666,7 @@ public class Launcher extends BaseActivity @Override public void bindAppInfosRemoved(final ArrayList appInfos) { - // Update AllApps - if (mAppsView != null) { - mAppsView.removeApps(appInfos); - } + mAppsView.getAppsStore().removeApps(appInfos); } @Override diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index de08eb667c..d4277dbde2 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -116,6 +116,8 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, mAH = new AdapterHolder[2]; mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */); mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */); + + mAllAppsStore.addUpdateListener(this::onAppsUpdated); } @Override @@ -150,42 +152,24 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } } + private void onAppsUpdated() { + if (FeatureFlags.ALL_APPS_TABS_ENABLED) { + boolean hasWorkApps = false; + for (AppInfo app : mAllAppsStore.getApps()) { + if (mWorkMatcher.matches(app, null)) { + hasWorkApps = true; + break; + } + } + rebindAdapters(hasWorkApps); + } + } + @Override public void setPressedIcon(BubbleTextView icon, Bitmap background) { mTouchFeedbackView.setPressedIcon(icon, background); } - /** - * Sets the current set of apps. - */ - public void setApps(List apps) { - boolean hasWorkProfileApp = hasWorkProfileApp(apps); - rebindAdapters(hasWorkProfileApp); - mAllAppsStore.setApps(apps); - } - - /** - * Adds or updates existing apps in the list - */ - public void addOrUpdateApps(List apps) { - mAllAppsStore.addOrUpdateApps(apps); - } - - /** - * Removes some apps from the list. - */ - public void removeApps(List apps) { - mAllAppsStore.removeApps(apps); - } - - public void updatePromiseAppProgress(PromiseAppInfo app) { - mAllAppsStore.updateAllIcons((child) -> { - if (child.getTag() == app) { - child.applyProgressLevel(app.level); - } - }); - } - /** * Returns whether the view itself will handle the touch event or not. */ @@ -324,18 +308,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, InsettableFrameLayout.dispatchInsets(this, insets); } - public void updateIconBadges(Set updatedBadges) { - PackageUserKey tempKey = new PackageUserKey(null, null); - mAllAppsStore.updateAllIcons((child) -> { - if (child.getTag() instanceof ItemInfo) { - ItemInfo info = (ItemInfo) child.getTag(); - if (tempKey.updateFromItemInfo(info) && updatedBadges.contains(tempKey)) { - child.applyBadgeState(info, true /* animate */); - } - } - }); - } - public SpringAnimationHandler getSpringAnimationHandler() { return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler; } @@ -371,17 +343,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, applyTouchDelegate(); } - private boolean hasWorkProfileApp(List apps) { - if (FeatureFlags.ALL_APPS_TABS_ENABLED) { - for (AppInfo app : apps) { - if (mWorkMatcher.matches(app, null)) { - return true; - } - } - } - return false; - } - private void replaceRVContainer(boolean showTabs) { for (int i = 0; i < mAH.length; i++) { if (mAH[i].recyclerView != null) { diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index 846b6a99c8..dc3489290d 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -20,22 +20,30 @@ import android.view.ViewGroup; import com.android.launcher3.AppInfo; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Set; /** * A utility class to maintain the collection of all apps. */ public class AllAppsStore { + private PackageUserKey mTempKey = new PackageUserKey(null, null); private final HashMap mComponentToAppMap = new HashMap<>(); private final List mUpdateListeners = new ArrayList<>(); private final ArrayList mIconContainers = new ArrayList<>(); + private boolean mDeferUpdates = false; + private boolean mUpdatePending = false; + public Collection getApps() { return mComponentToAppMap.values(); } @@ -52,6 +60,17 @@ public class AllAppsStore { return mComponentToAppMap.get(key); } + public void setDeferUpdates(boolean deferUpdates) { + if (mDeferUpdates != deferUpdates) { + mDeferUpdates = deferUpdates; + + if (!mDeferUpdates && mUpdatePending) { + notifyUpdate(); + mUpdatePending = false; + } + } + } + /** * Adds or updates existing apps in the list */ @@ -74,6 +93,10 @@ public class AllAppsStore { private void notifyUpdate() { + if (mDeferUpdates) { + mUpdatePending = true; + return; + } int count = mUpdateListeners.size(); for (int i = 0; i < count; i++) { mUpdateListeners.get(i).onAppsUpdated(); @@ -98,7 +121,26 @@ public class AllAppsStore { mIconContainers.remove(container); } - public void updateAllIcons(IconAction action) { + public void updateIconBadges(Set updatedBadges) { + updateAllIcons((child) -> { + if (child.getTag() instanceof ItemInfo) { + ItemInfo info = (ItemInfo) child.getTag(); + if (mTempKey.updateFromItemInfo(info) && updatedBadges.contains(mTempKey)) { + child.applyBadgeState(info, true /* animate */); + } + } + }); + } + + public void updatePromiseAppProgress(PromiseAppInfo app) { + updateAllIcons((child) -> { + if (child.getTag() == app) { + child.applyProgressLevel(app.level); + } + }); + } + + private void updateAllIcons(IconAction action) { for (int i = mIconContainers.size() - 1; i >= 0; i--) { ViewGroup parent = mIconContainers.get(i); int childCount = parent.getChildCount();