Handle IME selection focus for ENABLE_DEVICE_SEARCH

Bug: 162861289
Change-Id: I15e4eae09be2aa9f89a5157fd74c95e91e64bc53
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
index 7dc7bfc..b891120 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -310,4 +310,9 @@
     public Class<AppsDividerView> getTypeClass() {
         return AppsDividerView.class;
     }
+
+    @Override
+    public View getFocusedChild() {
+        return null;
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
index 8a810e3..d3c4c3d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -169,6 +169,7 @@
                 mDecorationHandler.extendBounds(getChildAt(i));
             }
             mDecorationHandler.onDraw(canvas);
+            mDecorationHandler.onFocusDraw(canvas, getFocusedChild());
         }
         mFocusHelper.draw(canvas);
         super.dispatchDraw(canvas);
@@ -183,7 +184,7 @@
 
     @Override
     public boolean shouldDraw() {
-        return getVisibility() != GONE;
+        return getVisibility() == VISIBLE;
     }
 
     @Override
@@ -364,4 +365,9 @@
     public Class<PredictionRowView> getTypeClass() {
         return PredictionRowView.class;
     }
+
+    @Override
+    public View getFocusedChild() {
+        return getChildAt(0);
+    }
 }
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 9a89dee..fe9717c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -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 -->
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 2d711e6..af3722a 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -527,6 +527,22 @@
         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 @@
             applyPadding();
             setupOverlay();
             if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-                recyclerView.addItemDecoration(new AllAppsSectionDecorator(getApps()));
+                recyclerView.addItemDecoration(new AllAppsSectionDecorator(
+                        AllAppsContainerView.this));
             }
         }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index ac55072..a168c06 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -21,6 +21,7 @@
 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 @@
  */
 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 @@
                     i = endIndex;
                     continue;
                 }
-
             }
             i++;
         }
@@ -78,13 +78,21 @@
         }
     }
 
-    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 @@
         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 @@
         }
 
         /**
-         * Draw bounds onto canvas
+         * Draw bounds onto canvas.
          */
         public void onDraw(Canvas canvas) {
             mPaint.setColor(mFillcolor);
@@ -130,7 +141,19 @@
         }
 
         /**
-         * 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();
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 9076f2a..7379dbed 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -224,6 +224,25 @@
     }
 
     /**
+     * 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
      */
     public int getNumAppRows() {
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderRow.java b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
index f899587..e357f61 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderRow.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
@@ -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 @@
     void setVerticalScroll(int scroll, boolean isScrolledOut);
 
     Class<? extends FloatingHeaderRow> getTypeClass();
+
+    /**
+     * Returns a child that has focus to be launched by the IME.
+     */
+    View getFocusedChild();
 }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 81e1b94..11d3fb9 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -38,6 +38,7 @@
 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 @@
         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);
diff --git a/src/com/android/launcher3/allapps/PluginHeaderRow.java b/src/com/android/launcher3/allapps/PluginHeaderRow.java
index 3089b18..cf7142c 100644
--- a/src/com/android/launcher3/allapps/PluginHeaderRow.java
+++ b/src/com/android/launcher3/allapps/PluginHeaderRow.java
@@ -83,4 +83,9 @@
     public Class<PluginHeaderRow> getTypeClass() {
         return PluginHeaderRow.class;
     }
+
+    @Override
+    public View getFocusedChild() {
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index db94e8b..06faaac 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -27,8 +27,11 @@
 
 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 @@
 
     @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;
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index c50189c..ae7ad10 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -32,6 +32,8 @@
 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 @@
 
     private ObjectAnimator mCurrentAnimation;
     private float mAlpha;
+    private float mRadius;
 
     public FocusIndicatorHelper(View container) {
         mContainer = container;
@@ -104,6 +107,9 @@
 
         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 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;
         }
     }