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