Support settings search in AllApps

[preview attached to  BR]

Bug: 166044087
Test: Manual
Change-Id: I997fc1c7e2e2c500f64858df9ccea4911e05d649
This commit is contained in:
Samuel Fufa
2020-08-23 15:58:39 -07:00
parent f5911b9ba0
commit a2d6a91be9
6 changed files with 235 additions and 7 deletions

View File

@@ -28,6 +28,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.recyclerview_recyclerview \
androidx.dynamicanimation_dynamicanimation \
androidx.preference_preference \
androidx.slice_slice-view \
iconloader_base
LOCAL_STATIC_JAVA_LIBRARIES := \

View File

@@ -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>

View File

@@ -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" />

View File

@@ -20,6 +20,7 @@ import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APP
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.ViewGroup;
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 @@ import java.util.List;
/**
* 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 class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
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 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
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 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
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 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
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 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
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 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
return item.viewType;
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}

View File

@@ -108,8 +108,8 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
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);

View File

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