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

Commit c7115ec8 authored by Abhilasha Chahal's avatar Abhilasha Chahal Committed by Android (Google) Code Review
Browse files

Merge "Revert "Revert "Extract out common adapter logic to support diff..."" into tm-dev

parents 8e432009 9c7096c8
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ import android.view.WindowInsets;
import androidx.recyclerview.widget.RecyclerView;

import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.BaseAdapterProvider;
import com.android.launcher3.allapps.BaseAllAppsAdapter;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.search.SearchAdapterProvider;

@@ -79,4 +82,11 @@ public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView<Taskba
        setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
        return super.onApplyWindowInsets(insets);
    }

    @Override
    protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<TaskbarAllAppsContext> mAppsList,
            BaseAdapterProvider[] adapterProviders) {
        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
                adapterProviders);
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -256,4 +256,11 @@ public class ActivityAllAppsContainerView<T extends BaseDraggingActivity> extend
        layoutParams.removeRule(RelativeLayout.BELOW);
        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
    }

    @Override
    protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
            BaseAdapterProvider[] adapterProviders) {
        return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
                adapterProviders);
    }
}
+28 −313
Original line number Diff line number Diff line
@@ -15,36 +15,20 @@
 */
package com.android.launcher3.allapps;

import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;

import android.content.Context;
import android.content.res.Resources;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityEventCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.views.ActivityContext;

import java.util.Arrays;
import java.util.List;

/**
@@ -53,111 +37,26 @@ import java.util.List;
 * @param <T> Type of context inflating all apps.
 */
public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
        RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
        BaseAllAppsAdapter<T> {

    public static final String TAG = "AppsGridAdapter";
    private final GridLayoutManager mGridLayoutMgr;
    private final GridSpanSizer mGridSizer;

    // A normal icon
    public static final int VIEW_TYPE_ICON = 1 << 1;
    // The message shown when there are no filtered results
    public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 2;
    // The message to continue to a market search when there are no filtered results
    public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 3;

    // We use various dividers for various purposes.  They share enough attributes to reuse layouts,
    // but differ in enough attributes to require different view types

    // A divider that separates the apps list and the search market button
    public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;

    // Common view type masks
    public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
    public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;


    private final BaseAdapterProvider[] mAdapterProviders;

    /**
     * ViewHolder for each icon.
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(View v) {
            super(v);
        }
    }

    /**
     * Info about a particular adapter item (can be either section or app)
     */
    public static class AdapterItem {
        /** Common properties */
        // The index of this adapter item in the list
        public int position;
        // The type of this item
        public int viewType;

        // The section name of this item.  Note that there can be multiple items with different
        // sectionNames in the same section
        public String sectionName = null;
        // The row that this item shows up on
        public int rowIndex;
        // The index of this app in the row
        public int rowAppIndex;
        // The associated ItemInfoWithIcon for the item
        public ItemInfoWithIcon itemInfo = null;
        // The index of this app not including sections
        public int appIndex = -1;
        // Search section associated to result
        public DecorationInfo decorationInfo = null;

        /**
         * Factory method for AppIcon AdapterItem
         */
        public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
                int appIndex) {
            AdapterItem item = new AdapterItem();
            item.viewType = VIEW_TYPE_ICON;
            item.position = pos;
            item.sectionName = sectionName;
            item.itemInfo = appInfo;
            item.appIndex = appIndex;
            return item;
        }

        /**
         * Factory method for empty search results view
         */
        public static AdapterItem asEmptySearch(int pos) {
            AdapterItem item = new AdapterItem();
            item.viewType = VIEW_TYPE_EMPTY_SEARCH;
            item.position = pos;
            return item;
        }

        /**
         * Factory method for a dividerView in AllAppsSearch
         */
        public static AdapterItem asAllAppsDivider(int pos) {
            AdapterItem item = new AdapterItem();
            item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
            item.position = pos;
            return item;
    public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
            AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
        super(activityContext, inflater, apps, adapterProviders);
        mGridSizer = new GridSpanSizer();
        mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
        mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
        setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
    }

    /**
         * Factory method for a market search button
     * Returns the grid layout manager.
     */
        public static AdapterItem asMarketSearch(int pos) {
            AdapterItem item = new AdapterItem();
            item.viewType = VIEW_TYPE_SEARCH_MARKET;
            item.position = pos;
            return item;
        }

        protected boolean isCountedForAccessibility() {
            return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
        }
    public RecyclerView.LayoutManager getLayoutManager() {
        return mGridLayoutMgr;
    }

    /**
@@ -217,7 +116,7 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
         */
        private int getRowsNotForAccessibility(int adapterPosition) {
            List<AdapterItem> items = mApps.getAdapterItems();
            adapterPosition = Math.max(adapterPosition, mApps.getAdapterItems().size() - 1);
            adapterPosition = Math.max(adapterPosition, items.size() - 1);
            int extraRows = 0;
            for (int i = 0; i <= adapterPosition; i++) {
                if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
@@ -228,73 +127,7 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
        }
    }

    /**
     * Helper class to size the grid items.
     */
    public class GridSpanSizer extends GridLayoutManager.SpanSizeLookup {

        public GridSpanSizer() {
            super();
            setSpanIndexCacheEnabled(true);
        }

    @Override
        public int getSpanSize(int position) {
            int viewType = mApps.getAdapterItems().get(position).viewType;
            int totalSpans = mGridLayoutMgr.getSpanCount();
            if (isIconViewType(viewType)) {
                return totalSpans / mAppsPerRow;
            } else {
                BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
                if (adapterProvider != null) {
                    return totalSpans / adapterProvider.getItemsPerRow(viewType, mAppsPerRow);
                }

                // Section breaks span the full width
                return totalSpans;
            }
        }
    }

    private final T mActivityContext;
    private final LayoutInflater mLayoutInflater;
    private final AlphabeticalAppsList<T> mApps;
    private final GridLayoutManager mGridLayoutMgr;
    private final GridSpanSizer mGridSizer;

    private final OnClickListener mOnIconClickListener;
    private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;

    private int mAppsPerRow;

    private OnFocusChangeListener mIconFocusListener;

    // The text to show when there are no search results and no market search handler.
    protected String mEmptySearchMessage;
    // The click listener to send off to the market app, updated each time the search query changes.
    private OnClickListener mMarketSearchClickListener;

    private final int mExtraHeight;

    public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
            AlphabeticalAppsList<T> apps, BaseAdapterProvider[] adapterProviders) {
        Resources res = activityContext.getResources();
        mActivityContext = activityContext;
        mApps = apps;
        mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
        mGridSizer = new GridSpanSizer();
        mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
        mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
        mLayoutInflater = inflater;

        mOnIconClickListener = mActivityContext.getItemOnClickListener();

        mAdapterProviders = adapterProviders;
        setAppsPerRow(mActivityContext.getDeviceProfile().numShownAllAppsColumns);
        mExtraHeight = mActivityContext.getResources().getDimensionPixelSize(
                R.dimen.all_apps_height_extra);
    }

    public void setAppsPerRow(int appsPerRow) {
        mAppsPerRow = appsPerRow;
        int totalSpans = mAppsPerRow;
@@ -309,148 +142,30 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
    }

    /**
     * Sets the long click listener for icons
     */
    public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
        mOnIconLongClickListener = listener;
    }

    public static boolean isDividerViewType(int viewType) {
        return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
    }

    public static boolean isIconViewType(int viewType) {
        return isViewType(viewType, VIEW_TYPE_MASK_ICON);
    }

    public static boolean isViewType(int viewType, int viewTypeMask) {
        return (viewType & viewTypeMask) != 0;
    }

    public void setIconFocusListener(OnFocusChangeListener focusListener) {
        mIconFocusListener = focusListener;
    }

    /**
     * Sets the last search query that was made, used to show when there are no results and to also
     * seed the intent for searching the market.
     */
    public void setLastSearchQuery(String query, OnClickListener marketSearchClickListener) {
        Resources res = mActivityContext.getResources();
        mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
        mMarketSearchClickListener = marketSearchClickListener;
    }

    /**
     * Returns the grid layout manager.
     * Helper class to size the grid items.
     */
    public GridLayoutManager getLayoutManager() {
        return mGridLayoutMgr;
    }
    public class GridSpanSizer extends GridLayoutManager.SpanSizeLookup {

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case VIEW_TYPE_ICON:
                int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
                        : R.layout.all_apps_icon_twoline;
                BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
                        layout, parent, false);
                icon.setLongPressTimeoutFactor(1f);
                icon.setOnFocusChangeListener(mIconFocusListener);
                icon.setOnClickListener(mOnIconClickListener);
                icon.setOnLongClickListener(mOnIconLongClickListener);
                // Ensure the all apps icon height matches the workspace icons in portrait mode.
                icon.getLayoutParams().height =
                        mActivityContext.getDeviceProfile().allAppsCellHeightPx;
                if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
                    icon.getLayoutParams().height += mExtraHeight;
                }
                return new ViewHolder(icon);
            case VIEW_TYPE_EMPTY_SEARCH:
                return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
                        parent, false));
            case VIEW_TYPE_SEARCH_MARKET:
                View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
                        parent, false);
                searchMarketView.setOnClickListener(mMarketSearchClickListener);
                return new ViewHolder(searchMarketView);
            case VIEW_TYPE_ALL_APPS_DIVIDER:
                return new ViewHolder(mLayoutInflater.inflate(
                        R.layout.all_apps_divider, parent, false));
            default:
                BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
                if (adapterProvider != null) {
                    return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
                }
                throw new RuntimeException("Unexpected view type" + viewType);
        }
        public GridSpanSizer() {
            super();
            setSpanIndexCacheEnabled(true);
        }

        @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        switch (holder.getItemViewType()) {
            case VIEW_TYPE_ICON:
                AdapterItem adapterItem = mApps.getAdapterItems().get(position);
                BubbleTextView icon = (BubbleTextView) holder.itemView;
                icon.reset();
                if (adapterItem.itemInfo instanceof AppInfo) {
                    icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
                } else {
                    icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
                }
                break;
            case VIEW_TYPE_EMPTY_SEARCH:
                TextView emptyViewText = (TextView) holder.itemView;
                emptyViewText.setText(mEmptySearchMessage);
                emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
                        Gravity.START | Gravity.CENTER_VERTICAL);
                break;
            case VIEW_TYPE_SEARCH_MARKET:
                TextView searchView = (TextView) holder.itemView;
                if (mMarketSearchClickListener != null) {
                    searchView.setVisibility(View.VISIBLE);
        public int getSpanSize(int position) {
            int viewType = mApps.getAdapterItems().get(position).viewType;
            int totalSpans = mGridLayoutMgr.getSpanCount();
            if (isIconViewType(viewType)) {
                return totalSpans / mAppsPerRow;
            } else {
                    searchView.setVisibility(View.GONE);
                }
                break;
            case VIEW_TYPE_ALL_APPS_DIVIDER:
                // nothing to do
                break;
            default:
                BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
                BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
                if (adapterProvider != null) {
                    adapterProvider.onBindView(holder, position);
                }
        }
    }

    @Override
    public void onViewRecycled(@NonNull ViewHolder holder) {
        super.onViewRecycled(holder);
    }

    @Override
    public boolean onFailedToRecycleView(ViewHolder holder) {
        // Always recycle and we will reset the view when it is bound
        return true;
                    return totalSpans / adapterProvider.getItemsPerRow(viewType, mAppsPerRow);
                }

    @Override
    public int getItemCount() {
        return mApps.getAdapterItems().size();
                // Section breaks span the full width
                return totalSpans;
            }

    @Override
    public int getItemViewType(int position) {
        AdapterItem item = mApps.getAdapterItems().get(position);
        return item.viewType;
        }

    @Nullable
    private BaseAdapterProvider getAdapterProvider(int viewType) {
        return Arrays.stream(mAdapterProviders).filter(
                adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
                null);
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.launcher3.allapps;

import android.content.Context;

import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -82,7 +82,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement

    // The of ordered component names as a result of a search query
    private ArrayList<AdapterItem> mSearchResults;
    private AllAppsGridAdapter<T> mAdapter;
    private BaseAllAppsAdapter<T> mAdapter;
    private AppInfoComparator mAppNameComparator;
    private final int mNumAppsPerRow;
    private int mNumAppRowsInAdapter;
@@ -106,7 +106,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
    /**
     * Sets the adapter to notify when this dataset changes.
     */
    public void setAdapter(AllAppsGridAdapter<T> adapter) {
    public void setAdapter(BaseAllAppsAdapter<T> adapter) {
        mAdapter = adapter;
    }

+333 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading