diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index f53a5efe95..7d494c28bf 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -130,7 +130,7 @@ public class PredictionRowView extends LinearLayout implements if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { mDecorationHandler = new AllAppsSectionDecorator.SectionDecorationHandler(getContext(), - false); + false, 0, true, true); } updateVisibility(); @@ -164,7 +164,7 @@ public class PredictionRowView extends LinearLayout implements for (int i = 0; i < childrenCount; i++) { mDecorationHandler.extendBounds(getChildAt(i)); } - mDecorationHandler.onDraw(canvas); + mDecorationHandler.onGroupDraw(canvas); mDecorationHandler.onFocusDraw(canvas, getFocusedChild()); mLauncher.getAppsView().getActiveRecyclerView().invalidateItemDecorations(); } diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f887d7b919..acc6466caa 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -254,11 +254,13 @@ 16sp - 15sp + 14sp 12sp 36dp 16dp 4dp + 28dp + 1dp 0dp diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index e5a4335dcd..ee4d7ecb55 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -53,7 +53,6 @@ import androidx.annotation.UiThread; import com.android.launcher3.Launcher.OnResumeCallback; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; -import com.android.launcher3.allapps.AllAppsSectionDecorator; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DraggableView; @@ -84,7 +83,7 @@ import java.text.NumberFormat; * too aggressive. */ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback, - IconLabelDotView, DraggableView, Reorderable, AllAppsSectionDecorator.SelfDecoratingView { + IconLabelDotView, DraggableView, Reorderable { private static final int DISPLAY_WORKSPACE = 0; private static final int DISPLAY_ALL_APPS = 1; @@ -954,16 +953,4 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, setCompoundDrawables(null, newIcon, null, null); } } - - @Override - public void decorate(int color) { - mHighlightColor = color; - invalidate(); - } - - @Override - public void removeDecoration() { - mHighlightColor = Color.TRANSPARENT; - invalidate(); - } } diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 715c142ac9..5030c5e1a3 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -42,8 +42,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.R; import com.android.launcher3.allapps.search.SearchAdapterProvider; -import com.android.launcher3.allapps.search.SearchSectionInfo; -import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.util.PackageManagerHelper; @@ -109,7 +108,7 @@ public class AllAppsGridAdapter extends // The index of this app not including sections public int appIndex = -1; // Search section associated to result - public SearchSectionInfo searchSectionInfo = null; + public SectionDecorationInfo sectionDecorationInfo = null; /** * Factory method for AppIcon AdapterItem @@ -372,10 +371,6 @@ public class AllAppsGridAdapter extends @Override public void onBindViewHolder(ViewHolder holder, int position) { - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() - && holder.itemView instanceof AllAppsSectionDecorator.SelfDecoratingView) { - ((AllAppsSectionDecorator.SelfDecoratingView) holder.itemView).removeDecoration(); - } switch (holder.getItemViewType()) { case VIEW_TYPE_ICON: AdapterItem adapterItem = mApps.getAdapterItems().get(position); @@ -409,10 +404,6 @@ public class AllAppsGridAdapter extends @Override public void onViewRecycled(@NonNull ViewHolder holder) { super.onViewRecycled(holder); - if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return; - if (holder.itemView instanceof AllAppsSectionDecorator.SelfDecoratingView) { - ((AllAppsSectionDecorator.SelfDecoratingView) holder.itemView).removeDecoration(); - } } @Override diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java index 6c95992397..176dce6c84 100644 --- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java +++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java @@ -18,16 +18,18 @@ package com.android.launcher3.allapps; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.RectF; import android.view.View; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager; -import com.android.launcher3.allapps.search.SearchSectionInfo; +import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.util.Themes; import java.util.List; @@ -45,52 +47,51 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { - // Iterate through views in recylerview and draw bounds around views in the same section. - // Since views in the same section will follow each other, we can skip to a last view in - // a section to get the bounds of the section without having to iterate on every item. - int itemCount = parent.getChildCount(); List adapterItems = mAppsView.getApps().getAdapterItems(); - SectionDecorationHandler lastDecorationHandler = null; - int i = 0; - while (i < itemCount) { + boolean drawFallbackFocusedView = true; + for (int i = 0; i < parent.getChildCount(); i++) { View view = parent.getChildAt(i); - if (view instanceof SelfDecoratingView) { - ((SelfDecoratingView) view).removeDecoration(); - } int position = parent.getChildAdapterPosition(view); AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position); - if (adapterItem.searchSectionInfo != null) { - SearchSectionInfo sectionInfo = adapterItem.searchSectionInfo; - int endIndex = Math.min(i + sectionInfo.getPosEnd() - position, itemCount - 1); + if (adapterItem.sectionDecorationInfo != null) { + SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo; SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler(); - if (decorationHandler != lastDecorationHandler && lastDecorationHandler != null) { - drawDecoration(c, lastDecorationHandler, parent); - } - lastDecorationHandler = decorationHandler; if (decorationHandler != null) { decorationHandler.extendBounds(view); - } - - if (endIndex > i) { - i = endIndex; - continue; + if (sectionInfo.isFocusedView()) { + decorationHandler.onFocusDraw(c, view); + drawFallbackFocusedView = false; + } else { + decorationHandler.onGroupDraw(c); + } } } - i++; } - if (lastDecorationHandler != null) { - drawDecoration(c, lastDecorationHandler, parent); + // fallback logic in case none of the SearchTarget is labeled as focused item + if (drawFallbackFocusedView) { + for (int i = 0; i < parent.getChildCount(); i++) { + View view = parent.getChildAt(i); + int position = parent.getChildAdapterPosition(view); + AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position); + if (adapterItem.sectionDecorationInfo != null) { + SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo; + SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler(); + if (decorationHandler != null) { + drawDecoration(c, decorationHandler, parent); + } + } + } } } - private void drawDecoration(Canvas c, SectionDecorationHandler decorationHandler, - RecyclerView parent) { - if (decorationHandler == null) return; + // Fallback logic in case non of the SearchTarget is labeled as focused item. + private void drawDecoration(@NonNull Canvas c, + @NonNull SectionDecorationHandler decorationHandler, + @NonNull RecyclerView parent) { if (decorationHandler.mIsFullWidth) { decorationHandler.mBounds.left = parent.getPaddingLeft(); decorationHandler.mBounds.right = parent.getWidth() - parent.getPaddingRight(); } - decorationHandler.onDraw(c); if (mAppsView.getFloatingHeaderView().getFocusedChild() == null && mAppsView.getApps().getFocusedChild() != null) { int index = mAppsView.getApps().getFocusedChildIndex(); @@ -109,23 +110,41 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { * Handles grouping and drawing of items in the same all apps sections. */ public static class SectionDecorationHandler { - private static final int FILL_ALPHA = 0; - protected RectF mBounds = new RectF(); private final boolean mIsFullWidth; private final float mRadius; - protected int mFocusColor; - protected int mFillcolor; + protected final int mFocusColor; // main focused item color + protected final int mFillcolor; // grouping color + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final boolean mIsTopRound; + private final boolean mIsBottomRound; + private float [] mCorners; + private float mFillSpacing; + public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha, + boolean isTopRound, boolean isBottomRound) { - public SectionDecorationHandler(Context context, boolean isFullWidth) { mIsFullWidth = isFullWidth; int endScrim = Themes.getColorBackground(context); - mFillcolor = ColorUtils.setAlphaComponent(endScrim, FILL_ALPHA); - mFocusColor = endScrim; - mRadius = Themes.getDialogCornerRadius(context); + mFillcolor = ColorUtils.setAlphaComponent(endScrim, fillAlpha); + mFocusColor = ColorUtils.setAlphaComponent(endScrim, fillAlpha); + + mIsTopRound = isTopRound; + mIsBottomRound = isBottomRound; + + mRadius = context.getResources().getDimensionPixelSize( + R.dimen.search_decoration_corner_radius); + mFillSpacing = context.getResources().getDimensionPixelSize( + R.dimen.search_decoration_padding); + mCorners = new float[]{ + mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top left radius in px + mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top right radius in px + mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0, // Bottom right + mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0 // Bottom left + }; + } /** @@ -147,9 +166,9 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { /** * Draw bounds onto canvas. */ - public void onDraw(Canvas canvas) { + public void onGroupDraw(Canvas canvas) { mPaint.setColor(mFillcolor); - canvas.drawRoundRect(mBounds, mRadius, mRadius, mPaint); + onDraw(canvas); } /** @@ -159,13 +178,20 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { if (view == null) { return; } - if (view instanceof SelfDecoratingView) { - ((SelfDecoratingView) view).decorate(mFocusColor); - return; - } mPaint.setColor(mFocusColor); - canvas.drawRoundRect(view.getLeft(), view.getTop(), - view.getRight(), view.getBottom(), mRadius, mRadius, mPaint); + mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); + onDraw(canvas); + } + + + private void onDraw(Canvas canvas) { + final Path path = new Path(); + RectF finalBounds = new RectF(mBounds.left + mFillSpacing, + mBounds.top + mFillSpacing, + mBounds.right - mFillSpacing, + mBounds.bottom - mFillSpacing); + path.addRoundRect(finalBounds, mCorners, Path.Direction.CW); + canvas.drawPath(path, mPaint); } /** @@ -175,19 +201,4 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { mBounds.setEmpty(); } } - - /** - * An interface for a view to draw highlight indicator - */ - public interface SelfDecoratingView { - /** - * Removes decorations drawing if focus is acquired by another view - */ - void removeDecoration(); - - /** - * Draws highlight indicator on view. - */ - void decorate(int focusColor); - } } diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 1dc10fea1f..123ace7938 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -20,7 +20,7 @@ import android.content.Context; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; -import com.android.launcher3.allapps.search.SearchSectionInfo; +import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.util.ItemInfoMatcher; @@ -201,20 +201,11 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { } void updateSearchAdapterItems(ArrayList list, int offset) { - SearchSectionInfo lastSection = null; for (int i = 0; i < list.size(); i++) { AdapterItem adapterItem = list.get(i); adapterItem.position = offset + i; mAdapterItems.add(adapterItem); - if (adapterItem.searchSectionInfo != lastSection) { - if (adapterItem.searchSectionInfo != null) { - adapterItem.searchSectionInfo.setPosStart(adapterItem.position); - } - if (lastSection != null) { - lastSection.setPosEnd(adapterItem.position - 1); - } - lastSection = adapterItem.searchSectionInfo; - } + if (adapterItem.isCountedForAccessibility()) { mAccessibilityResultsCount++; } @@ -295,16 +286,16 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { mFastScrollerSections.clear(); mAdapterItems.clear(); - SearchSectionInfo appSection = new SearchSectionInfo(); + SectionDecorationInfo appSection = new SectionDecorationInfo(); appSection.setDecorationHandler( - new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true)); + new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true, + 0, false, false)); // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the // ordered set of sections if (!hasFilter()) { mAccessibilityResultsCount = mApps.size(); - appSection.setPosStart(position); for (AppInfo info : mApps) { String sectionName = info.sectionName; @@ -321,11 +312,10 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { lastFastScrollerSectionInfo.fastScrollToItem = appItem; } if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - appItem.searchSectionInfo = appSection; + appItem.sectionDecorationInfo = appSection; } mAdapterItems.add(appItem); } - appSection.setPosEnd(mApps.isEmpty() ? appSection.getPosStart() : position - 1); } else { updateSearchAdapterItems(mSearchResults, 0); if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java index 84688e1737..f9fb22ece7 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java @@ -37,14 +37,14 @@ public class AppsSearchPipeline implements SearchPipeline { private static final int MAX_RESULTS_COUNT = 5; - private final SearchSectionInfo mSearchSectionInfo; + private final SectionDecorationInfo mSearchSectionInfo; private final LauncherAppState mLauncherAppState; public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) { mLauncherAppState = launcherAppState; - mSearchSectionInfo = new SearchSectionInfo(); + mSearchSectionInfo = new SectionDecorationInfo(); mSearchSectionInfo.setDecorationHandler( - new SectionDecorationHandler(context, true)); + new SectionDecorationHandler(context, true, 0, true, true)); } @Override @@ -81,7 +81,7 @@ public class AppsSearchPipeline implements SearchPipeline { ArrayList items = new ArrayList<>(); for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) { AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i); - appItem.searchSectionInfo = mSearchSectionInfo; + appItem.sectionDecorationInfo = mSearchSectionInfo; items.add(appItem); } diff --git a/src/com/android/launcher3/allapps/search/SearchSectionInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java similarity index 73% rename from src/com/android/launcher3/allapps/search/SearchSectionInfo.java rename to src/com/android/launcher3/allapps/search/SectionDecorationInfo.java index 464df68c96..0b64fcaece 100644 --- a/src/com/android/launcher3/allapps/search/SearchSectionInfo.java +++ b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java @@ -18,37 +18,30 @@ package com.android.launcher3.allapps.search; import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler; /** - * Info class for a search section + * Info class for a search section that is primarily used for decoration. */ -public class SearchSectionInfo { +public class SectionDecorationInfo { + + public static final int QUICK_LAUNCH = 1 << 0; + public static final int GROUPING = 1 << 1; private String mSectionId; + private boolean mFocused; private SectionDecorationHandler mDecorationHandler; - public int getPosStart() { - return mPosStart; + public boolean isFocusedView() { + return mFocused; } - public void setPosStart(int posStart) { - mPosStart = posStart; + public void setFocusedView(boolean focused) { + mFocused = focused; } - public int getPosEnd() { - return mPosEnd; - } - - public void setPosEnd(int posEnd) { - mPosEnd = posEnd; - } - - private int mPosStart; - private int mPosEnd; - - public SearchSectionInfo() { + public SectionDecorationInfo() { this(null); } - public SearchSectionInfo(String sectionId) { + public SectionDecorationInfo(String sectionId) { mSectionId = sectionId; } @@ -56,7 +49,6 @@ public class SearchSectionInfo { mDecorationHandler = sectionDecorationHandler; } - public SectionDecorationHandler getDecorationHandler() { return mDecorationHandler; }