Handle IME selection focus for ENABLE_DEVICE_SEARCH

Bug: 162861289
Change-Id: I15e4eae09be2aa9f89a5157fd74c95e91e64bc53
This commit is contained in:
Hyunyoung Song 2020-08-04 22:22:49 -07:00
parent 70a556da1d
commit 5dd045bec6
11 changed files with 138 additions and 21 deletions

View File

@ -310,4 +310,9 @@ public class AppsDividerView extends View implements StateListener<LauncherState
public Class<AppsDividerView> getTypeClass() {
return AppsDividerView.class;
}
@Override
public View getFocusedChild() {
return null;
}
}

View File

@ -169,6 +169,7 @@ public class PredictionRowView extends LinearLayout implements
mDecorationHandler.extendBounds(getChildAt(i));
}
mDecorationHandler.onDraw(canvas);
mDecorationHandler.onFocusDraw(canvas, getFocusedChild());
}
mFocusHelper.draw(canvas);
super.dispatchDraw(canvas);
@ -183,7 +184,7 @@ public class PredictionRowView extends LinearLayout implements
@Override
public boolean shouldDraw() {
return getVisibility() != GONE;
return getVisibility() == VISIBLE;
}
@Override
@ -364,4 +365,9 @@ public class PredictionRowView extends LinearLayout implements
public Class<PredictionRowView> getTypeClass() {
return PredictionRowView.class;
}
@Override
public View getFocusedChild() {
return getChildAt(0);
}
}

View File

@ -35,7 +35,8 @@
<color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
<color name="all_apps_section_fill">#327d7d7d</color>
<color name="all_apps_section_fill">#32c0c0c0</color>
<color name="all_apps_section_focused_item">#40c0c0c0</color>
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->

View File

@ -527,6 +527,22 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
}
/**
* Returns the ItemInfo of a view that is in focus, ready to be launched by an IME.
*/
public ItemInfo getHighlightedItemInfo() {
View view = getFloatingHeaderView().getFocusedChild();
if (view != null && view.getTag() instanceof ItemInfo) {
return ((ItemInfo) view.getTag());
}
if (getActiveRecyclerView().getApps().getFocusedChild() != null) {
// TODO: when new pipelines are included, getSearchResults
// should be supported at recycler view level and not apps list level.
return getActiveRecyclerView().getApps().getFocusedChild().appInfo;
}
return null;
}
public RecyclerViewFastScroller getScrollBar() {
AllAppsRecyclerView rv = getActiveRecyclerView();
return rv == null ? null : rv.getScrollbar();
@ -658,7 +674,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
applyPadding();
setupOverlay();
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
recyclerView.addItemDecoration(new AllAppsSectionDecorator(getApps()));
recyclerView.addItemDecoration(new AllAppsSectionDecorator(
AllAppsContainerView.this));
}
}

View File

@ -21,6 +21,7 @@ import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.R;
@ -34,19 +35,19 @@ import java.util.List;
*/
public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
private final AlphabeticalAppsList mApps;
private final AllAppsContainerView mAppsView;
AllAppsSectionDecorator(AlphabeticalAppsList appsList) {
mApps = appsList;
AllAppsSectionDecorator(AllAppsContainerView appsContainerView) {
mAppsView = appsContainerView;
}
@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 evert item.
// a section to get the bounds of the section without having to iterate on every item.
int itemCount = parent.getChildCount();
List<AlphabeticalAppsList.AdapterItem> adapterItems = mApps.getAdapterItems();
List<AlphabeticalAppsList.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
SectionDecorationHandler lastDecorationHandler = null;
int i = 0;
while (i < itemCount) {
@ -69,7 +70,6 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
i = endIndex;
continue;
}
}
i++;
}
@ -78,13 +78,21 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
}
}
private void drawDecoration(Canvas c, SectionDecorationHandler decorationHandler, View parent) {
private void drawDecoration(Canvas c, SectionDecorationHandler decorationHandler,
RecyclerView parent) {
if (decorationHandler == null) return;
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();
if (index >= 0 && index < parent.getChildCount()) {
decorationHandler.onFocusDraw(c, parent.getChildAt(index));
}
}
decorationHandler.reset();
}
@ -95,18 +103,21 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
protected RectF mBounds = new RectF();
private final boolean mIsFullWidth;
private final float mRadius;
private final int mFocusColor;
private final int mFillcolor;
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public SectionDecorationHandler(Context context, boolean isFullWidth) {
mIsFullWidth = isFullWidth;
mFillcolor = context.getColor(R.color.all_apps_section_fill);
mFocusColor = context.getColor(R.color.all_apps_section_focused_item);
mRadius = Themes.getDialogCornerRadius(context);
}
/**
* Extends current bounds to include view
* Extends current bounds to include the view.
*/
public void extendBounds(View view) {
if (mBounds.isEmpty()) {
@ -122,7 +133,7 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
}
/**
* Draw bounds onto canvas
* Draw bounds onto canvas.
*/
public void onDraw(Canvas canvas) {
mPaint.setColor(mFillcolor);
@ -130,7 +141,19 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
}
/**
* Reset view bounds to empty
* Draw the bound of the view to the canvas.
*/
public void onFocusDraw(Canvas canvas, @Nullable View view) {
if (view == null) {
return;
}
mPaint.setColor(mFocusColor);
canvas.drawRoundRect(view.getLeft(), view.getTop(),
view.getRight(), view.getBottom(), mRadius, mRadius, mPaint);
}
/**
* Reset view bounds to empty.
*/
public void reset() {
mBounds.setEmpty();

View File

@ -223,6 +223,25 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
return mAdapterItems;
}
/**
* Returns the child adapter item with IME launch focus.
*/
public AdapterItem getFocusedChild() {
return mAdapterItems.get(getFocusedChildIndex());
}
/**
* Returns the index of the child with IME launch focus.
*/
public int getFocusedChildIndex() {
for (AdapterItem item : mAdapterItems) {
if (item.isCountedForAccessibility()) {
return mAdapterItems.indexOf(item);
}
}
return -1;
}
/**
* Returns the number of rows of applications
*/

View File

@ -16,6 +16,7 @@
package com.android.launcher3.allapps;
import android.graphics.Rect;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
@ -55,4 +56,9 @@ public interface FloatingHeaderRow {
void setVerticalScroll(int scroll, boolean isScrolledOut);
Class<? extends FloatingHeaderRow> getTypeClass();
/**
* Returns a child that has focus to be launched by the IME.
*/
View getFocusedChild();
}

View File

@ -38,6 +38,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.systemui.plugins.AllAppsRow;
import com.android.systemui.plugins.AllAppsRow.OnHeightUpdatedListener;
@ -194,6 +195,19 @@ public class FloatingHeaderView extends LinearLayout implements
onHeightUpdated();
}
@Override
public View getFocusedChild() {
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
for (FloatingHeaderRow row : mAllRows) {
if (row.hasVisibleContent() && row.shouldDraw()) {
return row.getFocusedChild();
}
}
return null;
}
return super.getFocusedChild();
}
public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
for (FloatingHeaderRow row : mAllRows) {
row.setup(this, mAllRows, tabsHidden);

View File

@ -83,4 +83,9 @@ public class PluginHeaderRow implements FloatingHeaderRow {
public Class<PluginHeaderRow> getTypeClass() {
return PluginHeaderRow.class;
}
@Override
public View getFocusedChild() {
return null;
}
}

View File

@ -27,8 +27,11 @@ import android.widget.TextView.OnEditorActionListener;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.ArrayList;
@ -101,6 +104,16 @@ public class AllAppsSearchBarController
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
ItemInfo info = Launcher.getLauncher(mLauncher).getAppsView()
.getHighlightedItemInfo();
if (info != null) {
return mLauncher.startActivitySafely(v, info.getIntent(), info);
}
}
}
// Skip if it's not the right action
if (actionId != EditorInfo.IME_ACTION_SEARCH) {
return false;

View File

@ -32,6 +32,8 @@ import android.view.View;
import android.view.View.OnFocusChangeListener;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
/**
* A helper class to draw background of a focused view.
@ -93,6 +95,7 @@ public abstract class FocusIndicatorHelper implements
private ObjectAnimator mCurrentAnimation;
private float mAlpha;
private float mRadius;
public FocusIndicatorHelper(View container) {
mContainer = container;
@ -104,6 +107,9 @@ public abstract class FocusIndicatorHelper implements
setAlpha(0);
mShift = 0;
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
mRadius = Themes.getDialogCornerRadius(container.getContext());
}
}
protected void setAlpha(float alpha) {
@ -129,13 +135,15 @@ public abstract class FocusIndicatorHelper implements
}
public void draw(Canvas c) {
if (mAlpha > 0) {
Rect newRect = getDrawRect();
if (newRect != null) {
mDirtyRect.set(newRect);
c.drawRect(mDirtyRect, mPaint);
mIsDirty = true;
}
if (mAlpha <= 0) return;
Rect newRect = getDrawRect();
if (newRect != null) {
mDirtyRect.set(newRect);
c.drawRoundRect((float) mDirtyRect.left, (float) mDirtyRect.top,
(float) mDirtyRect.right, (float) mDirtyRect.bottom,
mRadius, mRadius, mPaint);
mIsDirty = true;
}
}