Support settings search in AllApps

[preview attached to  BR]

Bug: 166044087
Test: Manual
Change-Id: I997fc1c7e2e2c500f64858df9ccea4911e05d649
diff --git a/Android.mk b/Android.mk
index 752b530..25f5412 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,6 +28,7 @@
     androidx.recyclerview_recyclerview \
     androidx.dynamicanimation_dynamicanimation \
     androidx.preference_preference \
+    androidx.slice_slice-view \
     iconloader_base
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
diff --git a/res/layout/search_result_settings_row.xml b/res/layout/search_result_settings_row.xml
new file mode 100644
index 0000000..19daf34
--- /dev/null
+++ b/res/layout/search_result_settings_row.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.views.SearchSettingsRowView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/TextHeadline"
+    android:id="@+id/section_title"
+    android:background="?android:attr/selectableItemBackground"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center_vertical"
+    android:padding="4dp"
+    android:minHeight="48dp"
+    android:textColor="?android:attr/textColorPrimary"
+    android:textSize="14sp">
+
+    <TextView
+        android:id="@+id/title"
+        style="@style/TextTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="4dp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:textSize="16sp" />
+
+    <TextView
+        android:id="@+id/description"
+        style="@style/TextTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:textColor="?android:attr/textColorPrimary"
+        android:textSize="14sp" />
+
+    <TextView
+        android:id="@+id/breadcrumbs"
+        style="@style/TextTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:alpha=".7"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textSize="14sp" />
+
+
+</com.android.launcher3.views.SearchSettingsRowView>
\ No newline at end of file
diff --git a/res/layout/search_result_slice.xml b/res/layout/search_result_slice.xml
new file mode 100644
index 0000000..ea1d49a
--- /dev/null
+++ b/res/layout/search_result_slice.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<androidx.slice.widget.SliceView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingHorizontal="4dp" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index c61f01f..da161ac 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.net.Uri;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -30,18 +31,27 @@
 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.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.lifecycle.LiveData;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
 import com.android.launcher3.allapps.search.SearchSectionInfo;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -50,7 +60,9 @@
 /**
  * The grid view adapter of all the apps.
  */
-public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
+public class AllAppsGridAdapter extends
+        RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> implements
+        LifecycleOwner {
 
     public static final String TAG = "AppsGridAdapter";
 
@@ -71,12 +83,18 @@
 
     public static final int VIEW_TYPE_SEARCH_HERO_APP = 1 << 6;
 
-    public static final int DETAIL_ROW_WITH_BUTTON = 1 << 7;
+    public static final int VIEW_TYPE_SEARCH_ROW_WITH_BUTTON = 1 << 7;
+
+    public static final int VIEW_TYPE_SEARCH_ROW = 1 << 8;
+
+    public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 9;
 
     // 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 LifecycleRegistry mLifecycleRegistry;
+
     /**
      * ViewHolder for each icon.
      */
@@ -159,12 +177,15 @@
         boolean isCountedForAccessibility() {
             return viewType == VIEW_TYPE_ICON
                     || viewType == VIEW_TYPE_SEARCH_HERO_APP
-                    || viewType == DETAIL_ROW_WITH_BUTTON;
+                    || viewType == VIEW_TYPE_SEARCH_ROW_WITH_BUTTON
+                    || viewType == VIEW_TYPE_SEARCH_SLICE
+                    || viewType == VIEW_TYPE_SEARCH_ROW;
         }
     }
 
     /**
      * Extension of AdapterItem that contains an extra payload specific to item
+     *
      * @param <T> Play load Type
      */
     public static class AdapterItemWithPayload<T> extends AdapterItem {
@@ -310,6 +331,12 @@
         mOnIconClickListener = launcher.getItemOnClickListener();
 
         setAppsPerRow(mLauncher.getDeviceProfile().inv.numAllAppsColumns);
+        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+            mLifecycleRegistry = new LifecycleRegistry(this);
+            mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
+        } else {
+            mLifecycleRegistry = null;
+        }
     }
 
     public void setAppsPerRow(int appsPerRow) {
@@ -390,9 +417,15 @@
             case VIEW_TYPE_SEARCH_HERO_APP:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.search_result_hero_app, parent, false));
-            case DETAIL_ROW_WITH_BUTTON:
+            case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.search_result_play_item, parent, false));
+            case VIEW_TYPE_SEARCH_ROW:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.search_result_settings_row, parent, false));
+            case VIEW_TYPE_SEARCH_SLICE:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.search_result_slice, parent, false));
             default:
                 throw new RuntimeException("Unexpected view type");
         }
@@ -421,9 +454,20 @@
                     searchView.setVisibility(View.GONE);
                 }
                 break;
+            case VIEW_TYPE_SEARCH_SLICE:
+                SliceView sliceView = (SliceView) holder.itemView;
+                Uri uri = ((AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position))
+                        .getPayload();
+                try {
+                    LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher, uri);
+                    liveData.observe(this::getLifecycle, sliceView);
+                } catch (Exception ignored) {
+                }
+                break;
             case VIEW_TYPE_SEARCH_CORPUS_TITLE:
-            case DETAIL_ROW_WITH_BUTTON:
+            case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
             case VIEW_TYPE_SEARCH_HERO_APP:
+            case VIEW_TYPE_SEARCH_ROW:
                 PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
                 payloadResultView.applyAdapterInfo(
                         (AdapterItemWithPayload) mApps.getAdapterItems().get(position));
@@ -451,4 +495,9 @@
         return item.viewType;
     }
 
+    @NonNull
+    @Override
+    public Lifecycle getLifecycle() {
+        return mLifecycleRegistry;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 9534c85..0214c35 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -108,8 +108,8 @@
         private final boolean mIsFullWidth;
         private final float mRadius;
 
-        private final int mFocusColor;
-        private final int mFillcolor;
+        protected int mFocusColor;
+        protected int mFillcolor;
         private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
 
diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java
new file mode 100644
index 0000000..08c78ff
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchSettingsRowView.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+
+import java.util.ArrayList;
+
+/**
+ * A row of tappable TextViews with a breadcrumb for settings search.
+ */
+public class SearchSettingsRowView extends LinearLayout implements
+        View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+
+    private TextView mTitleView;
+    private TextView mDescriptionView;
+    private TextView mBreadcrumbsView;
+    private Intent mIntent;
+
+    public SearchSettingsRowView(@NonNull Context context) {
+        super(context);
+    }
+
+    public SearchSettingsRowView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SearchSettingsRowView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTitleView = findViewById(R.id.title);
+        mDescriptionView = findViewById(R.id.description);
+        mBreadcrumbsView = findViewById(R.id.breadcrumbs);
+        setOnClickListener(this);
+    }
+
+    @Override
+    public void applyAdapterInfo(
+            AllAppsGridAdapter.AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
+        Bundle bundle = adapterItemWithPayload.getPayload();
+        mIntent = bundle.getParcelable("intent");
+        showIfAvailable(mTitleView, bundle.getString("title"));
+        showIfAvailable(mDescriptionView, bundle.getString("description"));
+        ArrayList<String> breadcrumbs = bundle.getStringArrayList("breadcrumbs");
+        //TODO: implement RTL friendly breadcrumbs view
+        showIfAvailable(mBreadcrumbsView, breadcrumbs != null
+                ? String.join(" > ", breadcrumbs) : null);
+        adapterItemWithPayload.setSelectionHandler(() -> onClick(this));
+    }
+
+    private void showIfAvailable(TextView view, @Nullable String string) {
+        if (TextUtils.isEmpty(string)) {
+            view.setVisibility(GONE);
+        } else {
+            view.setVisibility(VISIBLE);
+            view.setText(string);
+        }
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (mIntent == null) return;
+        // TODO: create ItemInfo object and then use it to call startActivityForResult for proper
+        //  WW logging
+        Launcher launcher = Launcher.getLauncher(view.getContext());
+        launcher.startActivityForResult(mIntent, 0);
+    }
+}