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

Commit 3c5a08ad authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Implementing support for item diffing instead of creating out the

complete UI on every update

Bug: 229860311
Test: Verified locally
Change-Id: I5712b5d76878a0ed72cc1392ede59b3778b7a1dc
parent e73c3075
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -197,13 +196,6 @@ public abstract class BaseRecyclerView extends RecyclerView {
        if (mScrollbar != null) {
            mScrollbar.reattachThumbToScroll();
        }
        if (getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
            if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
                // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
                return;
            }
        }
        scrollToPosition(0);
    }
}
 No newline at end of file
+11 −5
Original line number Diff line number Diff line
@@ -29,11 +29,13 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.AppLauncher;

import java.util.ArrayList;
import java.util.Objects;

/**
@@ -95,14 +97,18 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
        mHeader.reset(false);
    }

    /** Invoke when the search results change. */
    public void onSearchResultsChanged() {
    /**
     * Sets results list for search
     */
    public void setSearchResults(ArrayList<AdapterItem> results) {
        if (getApps().setSearchResults(results)) {
            for (int i = 0; i < mAH.size(); i++) {
                if (mAH.get(i).mRecyclerView != null) {
                    mAH.get(i).mRecyclerView.onSearchResultsChanged();
                }
            }
        }
    }

    @Override
    protected final SearchAdapterProvider<?> createMainAdapterProvider() {
+2 −2
Original line number Diff line number Diff line
@@ -37,10 +37,10 @@ public class AllAppsFastScrollHelper {
     * Smooth scrolls the recycler view to the given section.
     */
    public void smoothScrollToSection(FastScrollSectionInfo info) {
        if (mTargetFastScrollPosition == info.fastScrollToItem.position) {
        if (mTargetFastScrollPosition == info.position) {
            return;
        }
        mTargetFastScrollPosition = info.fastScrollToItem.position;
        mTargetFastScrollPosition = info.position;
        mRv.getLayoutManager().startSmoothScroll(new MyScroller(mTargetFastScrollPosition));
    }

+27 −10
Original line number Diff line number Diff line
@@ -71,6 +71,26 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
        public void onChanged() {
            mCachedScrollPositions.clear();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            onChanged();
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            onChanged();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            onChanged();
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            onChanged();
        }
    };

    // The empty-search result background
@@ -241,17 +261,14 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
        // Find the fastscroll section that maps to this touch fraction
        List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections =
                mApps.getFastScrollerSections();
        AlphabeticalAppsList.FastScrollSectionInfo lastInfo = fastScrollSections.get(0);
        for (int i = 1; i < fastScrollSections.size(); i++) {
            AlphabeticalAppsList.FastScrollSectionInfo info = fastScrollSections.get(i);
            if (info.touchFraction > touchFraction) {
                break;
            }
            lastInfo = info;
        int count = fastScrollSections.size();
        if (count == 0) {
            return "";
        }

        mFastScrollHelper.smoothScrollToSection(lastInfo);
        return lastInfo.sectionName;
        int index = Utilities.boundToRange((int) (touchFraction * count), 0, count - 1);
        AlphabeticalAppsList.FastScrollSectionInfo section = fastScrollSections.get(index);
        mFastScrollHelper.smoothScrollToSection(section);
        return section.sectionName;
    }

    @Override
+61 −68
Original line number Diff line number Diff line
@@ -15,9 +15,14 @@
 */
package com.android.launcher3.allapps;

import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ALL_APPS_DIVIDER;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_EMPTY_SEARCH;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_SEARCH_MARKET;

import android.content.Context;

import androidx.recyclerview.widget.DiffUtil;

import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
@@ -51,14 +56,13 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
     */
    public static class FastScrollSectionInfo {
        // The section name
        public String sectionName;
        // The AdapterItem to scroll to for this section
        public AdapterItem fastScrollToItem;
        // The touch fraction that should map to this fast scroll section info
        public float touchFraction;
        public final String sectionName;
        // The item position
        public final int position;

        public FastScrollSectionInfo(String sectionName) {
        public FastScrollSectionInfo(String sectionName, int position) {
            this.sectionName = sectionName;
            this.position = position;
        }
    }

@@ -106,13 +110,6 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
        mAdapter = adapter;
    }

    /**
     * Returns all the apps.
     */
    public List<AppInfo> getApps() {
        return mApps;
    }

    /**
     * Returns fast scroller sections of all the current filtered applications.
     */
@@ -247,77 +244,49 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
     * mCachedSectionNames to have been calculated for the set of all apps in mApps.
     */
    public void updateAdapterItems() {
        refillAdapterItems();
        refreshRecyclerView();
    }

    private void refreshRecyclerView() {
        if (mAdapter != null) {
            mAdapter.notifyDataSetChanged();
        }
    }

    private void refillAdapterItems() {
        String lastSectionName = null;
        FastScrollSectionInfo lastFastScrollerSectionInfo = null;
        int position = 0;

        List<AdapterItem> oldItems = new ArrayList<>(mAdapterItems);
        // Prepare to update the list of sections, filtered apps, etc.
        mAccessibilityResultsCount = 0;
        mFastScrollerSections.clear();
        mAdapterItems.clear();
        mAccessibilityResultsCount = 0;

        // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
        // ordered set of sections

        if (!hasFilter()) {
            mAccessibilityResultsCount = mApps.size();
            int position = 0;
            if (mWorkAdapterProvider != null) {
                position += mWorkAdapterProvider.addWorkItems(mAdapterItems);
                if (!mWorkAdapterProvider.shouldShowWorkApps()) {
                    return;
                }
            }
            String lastSectionName = null;
            for (AppInfo info : mApps) {
                String sectionName = info.sectionName;
                mAdapterItems.add(AdapterItem.asApp(info));

                String sectionName = info.sectionName;
                // Create a new section if the section names do not match
                if (!sectionName.equals(lastSectionName)) {
                    lastSectionName = sectionName;
                    lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
                    mFastScrollerSections.add(lastFastScrollerSectionInfo);
                    mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
                }

                // Create an app item
                AdapterItem appItem = AdapterItem.asApp(position++, info);
                if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
                    lastFastScrollerSectionInfo.fastScrollToItem = appItem;
                }

                mAdapterItems.add(appItem);
                position++;
            }
        } else {
            int count = mSearchResults.size();
            for (int i = 0; i < count; i++) {
                AdapterItem adapterItem = mSearchResults.get(i);
                adapterItem.position = i;
                mAdapterItems.add(adapterItem);

                if (adapterItem.isCountedForAccessibility()) {
                    mAccessibilityResultsCount++;
                }
            }
            mAdapterItems.addAll(mSearchResults);
            if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
                // Append the search market item
                if (hasNoFilteredResults()) {
                    mAdapterItems.add(AdapterItem.asEmptySearch(position++));
                    mAdapterItems.add(new AdapterItem(VIEW_TYPE_EMPTY_SEARCH));
                } else {
                    mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
                    mAdapterItems.add(new AdapterItem(VIEW_TYPE_ALL_APPS_DIVIDER));
                }
                mAdapterItems.add(AdapterItem.asMarketSearch(position++));

                mAdapterItems.add(new AdapterItem(VIEW_TYPE_SEARCH_MARKET));
            }
        }
        mAccessibilityResultsCount = (int) mAdapterItems.stream()
                .filter(AdapterItem::isCountedForAccessibility).count();

        if (mNumAppsPerRowAllApps != 0) {
            // Update the number of rows in the adapter after we do all the merging (otherwise, we
            // would have to shift the values again)
@@ -340,19 +309,43 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
                }
            }
            mNumAppRowsInAdapter = rowIndex + 1;
        }

            // Pre-calculate all the fast scroller fractions
            float perSectionTouchFraction = 1f / mFastScrollerSections.size();
            float cumulativeTouchFraction = 0f;
            for (FastScrollSectionInfo info : mFastScrollerSections) {
                AdapterItem item = info.fastScrollToItem;
                if (!BaseAllAppsAdapter.isIconViewType(item.viewType)) {
                    info.touchFraction = 0f;
                    continue;
        if (mAdapter != null) {
            DiffUtil.calculateDiff(new MyDiffCallback(oldItems, mAdapterItems), false)
                    .dispatchUpdatesTo(mAdapter);
        }
                info.touchFraction = cumulativeTouchFraction;
                cumulativeTouchFraction += perSectionTouchFraction;
    }

    private static class MyDiffCallback extends DiffUtil.Callback {

        private final List<AdapterItem> mOldList;
        private final List<AdapterItem> mNewList;

        MyDiffCallback(List<AdapterItem> oldList, List<AdapterItem> newList) {
            mOldList = oldList;
            mNewList = newList;
        }

        @Override
        public int getOldListSize() {
            return mOldList.size();
        }

        @Override
        public int getNewListSize() {
            return mNewList.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return mOldList.get(oldItemPosition).isSameAs(mNewList.get(newItemPosition));
        }

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            return mOldList.get(oldItemPosition).isContentSame(mNewList.get(newItemPosition));
        }
    }

}
Loading