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

Commit a57dc7d4 authored by Sam Dubey's avatar Sam Dubey Committed by Android (Google) Code Review
Browse files

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

parents c19c0f9e 4f1a232c
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -25,9 +25,6 @@ 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;

@@ -82,11 +79,4 @@ 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);
    }
}
+0 −7
Original line number Diff line number Diff line
@@ -256,11 +256,4 @@ 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);
    }
}
+313 −28
Original line number Diff line number Diff line
@@ -15,20 +15,36 @@
 */
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;

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

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

    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);
    // 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);
        }
    }

    /**
     * Returns the grid layout manager.
     * Info about a particular adapter item (can be either section or app)
     */
    public RecyclerView.LayoutManager getLayoutManager() {
        return mGridLayoutMgr;
    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;
        }

        /**
         * Factory method for a market search button
         */
        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;
        }
    }

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

    @Override
    public void setAppsPerRow(int appsPerRow) {
        mAppsPerRow = appsPerRow;
        int totalSpans = mAppsPerRow;
        for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
            for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
                if (totalSpans % itemPerRow != 0) {
                    totalSpans *= itemPerRow;
                }
            }
        }
        mGridLayoutMgr.setSpanCount(totalSpans);
    }

    /**
     * Helper class to size the grid items.
     */
@@ -168,4 +255,202 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
            }
        }
    }

    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;
        for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
            for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
                if (totalSpans % itemPerRow != 0) {
                    totalSpans *= itemPerRow;
                }
            }
        }
        mGridLayoutMgr.setSpanCount(totalSpans);
    }

    /**
     * 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.
     */
    public GridLayoutManager getLayoutManager() {
        return mGridLayoutMgr;
    }

    @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);
        }
    }

    @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);
                } else {
                    searchView.setVisibility(View.GONE);
                }
                break;
            case VIEW_TYPE_ALL_APPS_DIVIDER:
                // nothing to do
                break;
            default:
                BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
                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;
    }

    @Override
    public int getItemCount() {
        return mApps.getAdapterItems().size();
    }

    @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.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.allapps.AllAppsGridAdapter.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 BaseAllAppsAdapter<T> mAdapter;
    private AllAppsGridAdapter<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(BaseAllAppsAdapter<T> adapter) {
    public void setAdapter(AllAppsGridAdapter<T> adapter) {
        mAdapter = adapter;
    }

+0 −333

File deleted.

Preview size limit exceeded, changes collapsed.

Loading