Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60180b04 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

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
parent 168ca694
Loading
Loading
Loading
Loading
+10 −29
Original line number Diff line number Diff line
@@ -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<PackageUserKey> 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<AppInfo> 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<AppInfo> 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<AppInfo> appInfos) {
        // Update AllApps
        if (mAppsView != null) {
            mAppsView.removeApps(appInfos);
        }
        mAppsView.getAppsStore().removeApps(appInfos);
    }

    @Override
+15 −54
Original line number Diff line number Diff line
@@ -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,40 +152,22 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
        }
    }

    @Override
    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
        mTouchFeedbackView.setPressedIcon(icon, background);
    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;
                }

    /**
     * Sets the current set of apps.
     */
    public void setApps(List<AppInfo> apps) {
        boolean hasWorkProfileApp = hasWorkProfileApp(apps);
        rebindAdapters(hasWorkProfileApp);
        mAllAppsStore.setApps(apps);
            }

    /**
     * Adds or updates existing apps in the list
     */
    public void addOrUpdateApps(List<AppInfo> apps) {
        mAllAppsStore.addOrUpdateApps(apps);
            rebindAdapters(hasWorkApps);
        }

    /**
     * Removes some apps from the list.
     */
    public void removeApps(List<AppInfo> apps) {
        mAllAppsStore.removeApps(apps);
    }

    public void updatePromiseAppProgress(PromiseAppInfo app) {
        mAllAppsStore.updateAllIcons((child) -> {
            if (child.getTag() == app) {
                child.applyProgressLevel(app.level);
            }
        });
    @Override
    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
        mTouchFeedbackView.setPressedIcon(icon, background);
    }

    /**
@@ -324,18 +308,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
        InsettableFrameLayout.dispatchInsets(this, insets);
    }

    public void updateIconBadges(Set<PackageUserKey> 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<AppInfo> 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) {
+43 −1
Original line number Diff line number Diff line
@@ -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<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
    private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>();
    private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();

    private boolean mDeferUpdates = false;
    private boolean mUpdatePending = false;

    public Collection<AppInfo> 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<PackageUserKey> 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();