Merge "Introduce support for play results in launcher" into ub-launcher3-master
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<?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.SearchResultPlayItem xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="horizontal">
|
||||
<View
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/deep_shortcut_icon_size"
|
||||
android:layout_height="@dimen/deep_shortcut_icon_size"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="@drawable/ic_deepshortcut_placeholder" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_view"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/try_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/search_action_try_now">
|
||||
</Button>
|
||||
|
||||
|
||||
</com.android.launcher3.views.SearchResultPlayItem>
|
||||
@@ -13,11 +13,11 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/section_title"
|
||||
android:textSize="14sp"
|
||||
android:fontFamily="@style/TextHeadline"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:padding="4dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
<com.android.launcher3.views.SearchSectionHeaderView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/section_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@style/TextHeadline"
|
||||
android:padding="4dp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="14sp" />
|
||||
@@ -70,6 +70,8 @@
|
||||
<!--All apps Search-->
|
||||
<!-- Section title for apps [CHAR_LIMIT=50] -->
|
||||
<string name="search_corpus_apps">Apps</string>
|
||||
<!-- try instant app action for play search result [CHAR_LIMIT=50 -->
|
||||
<string name="search_action_try_now">Try Now</string>
|
||||
|
||||
<!-- Popup items -->
|
||||
<!-- Text to display as the header above notifications. [CHAR_LIMIT=30] -->
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
|
||||
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
|
||||
@@ -527,6 +529,25 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles selection on focused view and returns success
|
||||
*/
|
||||
public boolean selectFocusedView(View v) {
|
||||
ItemInfo itemInfo = getHighlightedItemInfo();
|
||||
if (itemInfo != null) {
|
||||
return mLauncher.startActivitySafely(v, itemInfo.getIntent(), itemInfo);
|
||||
}
|
||||
AdapterItem focusedItem = getActiveRecyclerView().getApps().getFocusedChild();
|
||||
if (focusedItem instanceof AdapterItemWithPayload) {
|
||||
Runnable onSelection = ((AdapterItemWithPayload) focusedItem).getSelectionHandler();
|
||||
if (onSelection != null) {
|
||||
onSelection.run();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ItemInfo of a view that is in focus, ready to be launched by an IME.
|
||||
*/
|
||||
|
||||
@@ -40,10 +40,10 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
||||
import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
|
||||
import com.android.launcher3.allapps.search.SearchSectionInfo;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.views.HeroSearchResultView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -71,6 +71,8 @@ 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;
|
||||
|
||||
// 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;
|
||||
@@ -85,6 +87,108 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Info about a particular adapter item (can be either section or app)
|
||||
*/
|
||||
public static class AdapterItem {
|
||||
/** Common properties */
|
||||
// The index of this adapter item in the list
|
||||
public int position;
|
||||
// The type of this item
|
||||
public int viewType;
|
||||
|
||||
/** App-only properties */
|
||||
// The section name of this app. Note that there can be multiple items with different
|
||||
// sectionNames in the same section
|
||||
public String sectionName = null;
|
||||
// The row that this item shows up on
|
||||
public int rowIndex;
|
||||
// The index of this app in the row
|
||||
public int rowAppIndex;
|
||||
// The associated AppInfo for the app
|
||||
public AppInfo appInfo = null;
|
||||
// The index of this app not including sections
|
||||
public int appIndex = -1;
|
||||
// Search section associated to result
|
||||
public SearchSectionInfo searchSectionInfo = null;
|
||||
|
||||
/**
|
||||
* Factory method for AppIcon AdapterItem
|
||||
*/
|
||||
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
||||
int appIndex) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ICON;
|
||||
item.position = pos;
|
||||
item.sectionName = sectionName;
|
||||
item.appInfo = appInfo;
|
||||
item.appIndex = appIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for empty search results view
|
||||
*/
|
||||
public static AdapterItem asEmptySearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_EMPTY_SEARCH;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a dividerView in AllAppsSearch
|
||||
*/
|
||||
public static AdapterItem asAllAppsDivider(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a market search button
|
||||
*/
|
||||
public static AdapterItem asMarketSearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_SEARCH_MARKET;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
boolean isCountedForAccessibility() {
|
||||
return viewType == VIEW_TYPE_ICON
|
||||
|| viewType == VIEW_TYPE_SEARCH_HERO_APP
|
||||
|| viewType == DETAIL_ROW_WITH_BUTTON;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of AdapterItem that contains an extra payload specific to item
|
||||
* @param <T> Play load Type
|
||||
*/
|
||||
public static class AdapterItemWithPayload<T> extends AdapterItem {
|
||||
private T mPayload;
|
||||
private Runnable mSelectionHandler;
|
||||
|
||||
public AdapterItemWithPayload(T payload, int type) {
|
||||
mPayload = payload;
|
||||
viewType = type;
|
||||
}
|
||||
|
||||
public void setSelectionHandler(Runnable runnable) {
|
||||
mSelectionHandler = runnable;
|
||||
}
|
||||
|
||||
public Runnable getSelectionHandler() {
|
||||
return mSelectionHandler;
|
||||
}
|
||||
|
||||
public T getPayload() {
|
||||
return mPayload;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A subclass of GridLayoutManager that overrides accessibility values during app search.
|
||||
*/
|
||||
@@ -286,6 +390,9 @@ 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:
|
||||
return new ViewHolder(mLayoutInflater.inflate(
|
||||
R.layout.search_result_play_item, parent, false));
|
||||
default:
|
||||
throw new RuntimeException("Unexpected view type");
|
||||
}
|
||||
@@ -315,15 +422,11 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
}
|
||||
break;
|
||||
case VIEW_TYPE_SEARCH_CORPUS_TITLE:
|
||||
TextView titleView = (TextView) holder.itemView;
|
||||
titleView.setText(mApps.getAdapterItems().get(position).searchSectionInfo.getTitle(
|
||||
titleView.getContext()));
|
||||
break;
|
||||
case DETAIL_ROW_WITH_BUTTON:
|
||||
case VIEW_TYPE_SEARCH_HERO_APP:
|
||||
HeroSearchResultView heroView = (HeroSearchResultView) holder.itemView;
|
||||
heroView.prepareUsingAdapterItem(
|
||||
(AlphabeticalAppsList.HeroAppAdapterItem) mApps.getAdapterItems().get(
|
||||
position));
|
||||
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
|
||||
payloadResultView.applyAdapterInfo(
|
||||
(AdapterItemWithPayload) mApps.getAdapterItems().get(position));
|
||||
break;
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
// nothing to do
|
||||
@@ -344,7 +447,7 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
|
||||
AdapterItem item = mApps.getAdapterItems().get(position);
|
||||
return item.viewType;
|
||||
}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
if (mApps == null) {
|
||||
return;
|
||||
}
|
||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
|
||||
|
||||
// Skip early if there are no items or we haven't been measured
|
||||
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
||||
@@ -352,7 +352,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
@Override
|
||||
public int getCurrentScrollY() {
|
||||
// Return early if there are no items or we haven't been measured
|
||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
|
||||
if (items.isEmpty() || mNumAppsPerRow == 0 || getChildCount() == 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -368,14 +368,14 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
}
|
||||
|
||||
public int getCurrentScrollY(int position, int offset) {
|
||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
AlphabeticalAppsList.AdapterItem posItem = position < items.size() ?
|
||||
items.get(position) : null;
|
||||
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
|
||||
AllAppsGridAdapter.AdapterItem posItem = position < items.size()
|
||||
? items.get(position) : null;
|
||||
int y = mCachedScrollPositions.get(position, -1);
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
for (int i = 0; i < position; i++) {
|
||||
AlphabeticalAppsList.AdapterItem item = items.get(i);
|
||||
AllAppsGridAdapter.AdapterItem item = items.get(i);
|
||||
if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
|
||||
// Break once we reach the desired row
|
||||
if (posItem != null && posItem.viewType == item.viewType &&
|
||||
|
||||
@@ -47,13 +47,13 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration {
|
||||
// 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 every item.
|
||||
int itemCount = parent.getChildCount();
|
||||
List<AlphabeticalAppsList.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
|
||||
List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
|
||||
SectionDecorationHandler lastDecorationHandler = null;
|
||||
int i = 0;
|
||||
while (i < itemCount) {
|
||||
View view = parent.getChildAt(i);
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
AlphabeticalAppsList.AdapterItem adapterItem = adapterItems.get(position);
|
||||
AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position);
|
||||
if (adapterItem.searchSectionInfo != null) {
|
||||
SearchSectionInfo sectionInfo = adapterItem.searchSectionInfo;
|
||||
int endIndex = Math.min(i + sectionInfo.getPosEnd() - position, itemCount - 1);
|
||||
|
||||
@@ -19,10 +19,10 @@ package com.android.launcher3.allapps;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.search.SearchSectionInfo;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LabelComparator;
|
||||
|
||||
@@ -62,101 +62,6 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Info about a particular adapter item (can be either section or app)
|
||||
*/
|
||||
public static class AdapterItem {
|
||||
/** Common properties */
|
||||
// The index of this adapter item in the list
|
||||
public int position;
|
||||
// The type of this item
|
||||
public int viewType;
|
||||
|
||||
/** App-only properties */
|
||||
// The section name of this app. Note that there can be multiple items with different
|
||||
// sectionNames in the same section
|
||||
public String sectionName = null;
|
||||
// The row that this item shows up on
|
||||
public int rowIndex;
|
||||
// The index of this app in the row
|
||||
public int rowAppIndex;
|
||||
// The associated AppInfo for the app
|
||||
public AppInfo appInfo = null;
|
||||
// The index of this app not including sections
|
||||
public int appIndex = -1;
|
||||
// Search section associated to result
|
||||
public SearchSectionInfo searchSectionInfo = null;
|
||||
|
||||
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
||||
int appIndex) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_ICON;
|
||||
item.position = pos;
|
||||
item.sectionName = sectionName;
|
||||
item.appInfo = appInfo;
|
||||
item.appIndex = appIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
public static AdapterItem asEmptySearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
public static AdapterItem asAllAppsDivider(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
public static AdapterItem asMarketSearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for search section title AdapterItem
|
||||
*/
|
||||
public static AdapterItem asSearchTitle(SearchSectionInfo sectionInfo, int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_CORPUS_TITLE;
|
||||
item.position = pos;
|
||||
item.searchSectionInfo = sectionInfo;
|
||||
return item;
|
||||
}
|
||||
|
||||
boolean isCountedForAccessibility() {
|
||||
return viewType == AllAppsGridAdapter.VIEW_TYPE_ICON
|
||||
|| viewType == AllAppsGridAdapter.VIEW_TYPE_SEARCH_HERO_APP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of AdapterItem that contains shortcut workspace items
|
||||
*/
|
||||
public static class HeroAppAdapterItem extends AdapterItem {
|
||||
private ArrayList<WorkspaceItemInfo> mShortcutInfos;
|
||||
|
||||
public HeroAppAdapterItem(AppInfo info, ArrayList<WorkspaceItemInfo> shortcutInfos) {
|
||||
viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_HERO_APP;
|
||||
mShortcutInfos = shortcutInfos;
|
||||
appInfo = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of shortcuts for appInfo
|
||||
*/
|
||||
public ArrayList<WorkspaceItemInfo> getShortcutInfos() {
|
||||
return mShortcutInfos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private final BaseDraggingActivity mLauncher;
|
||||
|
||||
@@ -396,7 +301,9 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||
adapterItem.position = i;
|
||||
mAdapterItems.add(adapterItem);
|
||||
if (adapterItem.searchSectionInfo != lastSection) {
|
||||
adapterItem.searchSectionInfo.setPosStart(i);
|
||||
if (adapterItem.searchSectionInfo != null) {
|
||||
adapterItem.searchSectionInfo.setPosStart(i);
|
||||
}
|
||||
if (lastSection != null) {
|
||||
lastSection.setPosEnd(i - 1);
|
||||
}
|
||||
|
||||
@@ -15,35 +15,26 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
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.allapps.AllAppsGridAdapter;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.systemui.plugins.AllAppsSearchPlugin;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -54,17 +45,14 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class AllAppsSearchBarController
|
||||
implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
|
||||
OnFocusChangeListener, PluginListener<AllAppsSearchPlugin> {
|
||||
OnFocusChangeListener {
|
||||
|
||||
private static final String TAG = "AllAppsSearchBarContoller";
|
||||
protected BaseDraggingActivity mLauncher;
|
||||
protected Callbacks mCb;
|
||||
protected ExtendedEditText mInput;
|
||||
protected String mQuery;
|
||||
|
||||
protected SearchAlgorithm mSearchAlgorithm;
|
||||
private AllAppsSearchPlugin mPlugin;
|
||||
private Consumer mPlubinCb;
|
||||
|
||||
public void setVisibility(int visibility) {
|
||||
mInput.setVisibility(visibility);
|
||||
@@ -85,18 +73,13 @@ public class AllAppsSearchBarController
|
||||
mInput.setOnBackKeyListener(this);
|
||||
mInput.setOnFocusChangeListener(this);
|
||||
mSearchAlgorithm = searchAlgorithm;
|
||||
|
||||
PluginManagerWrapper.INSTANCE.get(launcher).addPluginListener(this,
|
||||
AllAppsSearchPlugin.class);
|
||||
mPlubinCb = secondaryCb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
if (mPlugin != null) {
|
||||
if (s.length() == 0) {
|
||||
mPlugin.startedTyping();
|
||||
}
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
if (mSearchAlgorithm instanceof PluginWrapper) {
|
||||
((PluginWrapper) mSearchAlgorithm).runOnPluginIfConnected(
|
||||
AllAppsSearchPlugin::startedTyping);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,9 +97,6 @@ public class AllAppsSearchBarController
|
||||
} else {
|
||||
mSearchAlgorithm.cancel(false);
|
||||
mSearchAlgorithm.doSearch(mQuery, mCb);
|
||||
if (mPlugin != null) {
|
||||
mPlugin.performSearch(mQuery, mPlubinCb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,10 +113,8 @@ public class AllAppsSearchBarController
|
||||
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);
|
||||
if (Launcher.getLauncher(mLauncher).getAppsView().selectFocusedView(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,43 +175,14 @@ public class AllAppsSearchBarController
|
||||
return mInput.isFocused();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(AllAppsSearchPlugin allAppsSearchPlugin, Context context) {
|
||||
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
|
||||
mPlugin = allAppsSearchPlugin;
|
||||
checkCallPermission();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check call permissions.
|
||||
* A wrapper setup for running essential calls to plugin from search controller
|
||||
*/
|
||||
public void checkCallPermission() {
|
||||
final String[] permission = {"android.permission.CALL_PHONE",
|
||||
"android.permission.READ_CONTACTS"};
|
||||
boolean request = false;
|
||||
for (String p : permission) {
|
||||
int permissionCheck = ContextCompat.checkSelfPermission(mLauncher, p);
|
||||
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
|
||||
request = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!request) return;
|
||||
boolean rationale = false;
|
||||
for (String p : permission) {
|
||||
if (mLauncher.shouldShowRequestPermissionRationale(p)) {
|
||||
rationale = true;
|
||||
}
|
||||
if (rationale) {
|
||||
Log.e(TAG, p + " Show rationale");
|
||||
Toast.makeText(mLauncher, "Requesting Permissions", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(mLauncher, permission, 123);
|
||||
Log.e(TAG, p + " request permission");
|
||||
}
|
||||
}
|
||||
|
||||
public interface PluginWrapper {
|
||||
/**
|
||||
* executes call if plugin is connected
|
||||
*/
|
||||
void runOnPluginIfConnected(Consumer<AllAppsSearchPlugin> plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,11 +195,23 @@ public class AllAppsSearchBarController
|
||||
*
|
||||
* @param items sorted list of search result adapter items.
|
||||
*/
|
||||
void onSearchResult(String query, ArrayList<AlphabeticalAppsList.AdapterItem> items);
|
||||
void onSearchResult(String query, ArrayList<AllAppsGridAdapter.AdapterItem> items);
|
||||
|
||||
/**
|
||||
* Called when the search results should be cleared.
|
||||
*/
|
||||
void clearSearchResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for supporting dynamic search results
|
||||
*
|
||||
* @param <T> Type of payload
|
||||
*/
|
||||
public interface PayloadResultHandler<T> {
|
||||
/**
|
||||
* Updates View using Adapter's payload
|
||||
*/
|
||||
void applyAdapterInfo(AdapterItemWithPayload<T> adapterItemWithPayload);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||
import com.android.launcher3.allapps.SearchUiManager;
|
||||
@@ -172,7 +173,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearchResult(String query, ArrayList<AlphabeticalAppsList.AdapterItem> items) {
|
||||
public void onSearchResult(String query, ArrayList<AllAppsGridAdapter.AdapterItem> items) {
|
||||
if (items != null) {
|
||||
mApps.setSearchResults(items);
|
||||
notifyResultChanged();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.allapps.search;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
|
||||
import static com.android.launcher3.allapps.AllAppsGridAdapter.VIEW_TYPE_SEARCH_HERO_APP;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
@@ -23,9 +24,9 @@ import android.content.pm.ShortcutInfo;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList.HeroAppAdapterItem;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.AllAppsList;
|
||||
import com.android.launcher3.model.BaseModelUpdateTask;
|
||||
@@ -82,7 +83,7 @@ public class AppsSearchPipeline implements SearchPipeline {
|
||||
|
||||
/**
|
||||
* Returns MAX_SHORTCUTS_COUNT shortcuts from local cache
|
||||
* TODO: Shortcuts should be ranked based on relevancy
|
||||
* TODO: Shortcuts should be ranked based on relevancy
|
||||
*/
|
||||
private ArrayList<WorkspaceItemInfo> getShortcutInfos(Context context, AppInfo appInfo) {
|
||||
List<ShortcutInfo> shortcuts = new ShortcutRequest(context, appInfo.user)
|
||||
@@ -126,7 +127,9 @@ public class AppsSearchPipeline implements SearchPipeline {
|
||||
//hero app
|
||||
AppInfo appInfo = apps.get(i);
|
||||
ArrayList<WorkspaceItemInfo> shortcuts = getShortcutInfos(context, appInfo);
|
||||
AdapterItem adapterItem = new HeroAppAdapterItem(appInfo, shortcuts);
|
||||
AdapterItem adapterItem = new AllAppsGridAdapter.AdapterItemWithPayload(shortcuts,
|
||||
VIEW_TYPE_SEARCH_HERO_APP);
|
||||
adapterItem.appInfo = appInfo;
|
||||
adapterItem.searchSectionInfo = mSearchSectionInfo;
|
||||
adapterItems.add(adapterItem);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps.search;
|
||||
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
@@ -28,5 +28,5 @@ public interface SearchPipeline {
|
||||
/**
|
||||
* Perform query
|
||||
*/
|
||||
void performSearch(String query, Consumer<ArrayList<AlphabeticalAppsList.AdapterItem>> cb);
|
||||
void performSearch(String query, Consumer<ArrayList<AllAppsGridAdapter.AdapterItem>> cb);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps.search;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler;
|
||||
|
||||
/**
|
||||
@@ -24,7 +22,7 @@ import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHa
|
||||
*/
|
||||
public class SearchSectionInfo {
|
||||
|
||||
private final int mTitleResId;
|
||||
private String mTitle;
|
||||
private SectionDecorationHandler mDecorationHandler;
|
||||
|
||||
public int getPosStart() {
|
||||
@@ -47,11 +45,11 @@ public class SearchSectionInfo {
|
||||
private int mPosEnd;
|
||||
|
||||
public SearchSectionInfo() {
|
||||
this(-1);
|
||||
this(null);
|
||||
}
|
||||
|
||||
public SearchSectionInfo(int titleResId) {
|
||||
mTitleResId = titleResId;
|
||||
public SearchSectionInfo(String title) {
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
public void setDecorationHandler(SectionDecorationHandler sectionDecorationHandler) {
|
||||
@@ -66,10 +64,7 @@ public class SearchSectionInfo {
|
||||
/**
|
||||
* Returns the section's title
|
||||
*/
|
||||
public String getTitle(Context context) {
|
||||
if (mTitleResId == -1) {
|
||||
return "";
|
||||
}
|
||||
return context.getString(mTitleResId);
|
||||
public String getTitle() {
|
||||
return mTitle == null ? "" : mTitle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
|
||||
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.dragndrop.DraggableView;
|
||||
import com.android.launcher3.graphics.DragPreviewProvider;
|
||||
@@ -47,7 +48,8 @@ import java.util.List;
|
||||
/**
|
||||
* A view representing a high confidence app search result that includes shortcuts
|
||||
*/
|
||||
public class HeroSearchResultView extends LinearLayout implements DragSource {
|
||||
public class HeroSearchResultView extends LinearLayout implements DragSource,
|
||||
AllAppsSearchBarController.PayloadResultHandler<List<WorkspaceItemInfo>> {
|
||||
|
||||
BubbleTextView mBubbleTextView;
|
||||
View mIconView;
|
||||
@@ -96,18 +98,18 @@ public class HeroSearchResultView extends LinearLayout implements DragSource {
|
||||
/**
|
||||
* Apply {@link ItemInfo} for appIcon and shortcut Icons
|
||||
*/
|
||||
public void prepareUsingAdapterItem(AlphabeticalAppsList.HeroAppAdapterItem adapterItem) {
|
||||
@Override
|
||||
public void applyAdapterInfo(AdapterItemWithPayload<List<WorkspaceItemInfo>> adapterItem) {
|
||||
mBubbleTextView.applyFromApplicationInfo(adapterItem.appInfo);
|
||||
mIconView.setBackground(mBubbleTextView.getIcon());
|
||||
mIconView.setTag(adapterItem.appInfo);
|
||||
List<WorkspaceItemInfo> shorcutInfos = adapterItem.getShortcutInfos();
|
||||
List<WorkspaceItemInfo> shorcutInfos = adapterItem.getPayload();
|
||||
for (int i = 0; i < mDeepShortcutTextViews.length; i++) {
|
||||
mDeepShortcutTextViews[i].setVisibility(shorcutInfos.size() > i ? VISIBLE : GONE);
|
||||
if (i < shorcutInfos.size()) {
|
||||
mDeepShortcutTextViews[i].applyFromWorkspaceItem(shorcutInfos.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,7 +128,6 @@ public class HeroSearchResultView extends LinearLayout implements DragSource {
|
||||
mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drag and drop handler for popup items in Launcher activity
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
|
||||
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* A View representing a PlayStore item.
|
||||
*/
|
||||
public class SearchResultPlayItem extends LinearLayout implements
|
||||
AllAppsSearchBarController.PayloadResultHandler<Bundle> {
|
||||
private final DeviceProfile mDeviceProfile;
|
||||
private View mIconView;
|
||||
private TextView mTitleView;
|
||||
private TextView[] mDetailViews = new TextView[3];
|
||||
private Button mPreviewButton;
|
||||
private String mPackageName;
|
||||
private boolean mIsInstantGame;
|
||||
|
||||
public SearchResultPlayItem(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public SearchResultPlayItem(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SearchResultPlayItem(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mDeviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mIconView = findViewById(R.id.icon);
|
||||
mTitleView = findViewById(R.id.title_view);
|
||||
mPreviewButton = findViewById(R.id.try_button);
|
||||
mPreviewButton.setOnClickListener(view -> launchInstantGame());
|
||||
mDetailViews[0] = findViewById(R.id.detail_0);
|
||||
mDetailViews[1] = findViewById(R.id.detail_1);
|
||||
mDetailViews[2] = findViewById(R.id.detail_2);
|
||||
|
||||
ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
|
||||
iconParams.height = mDeviceProfile.allAppsIconSizePx;
|
||||
iconParams.width = mDeviceProfile.allAppsIconSizePx;
|
||||
setOnClickListener(view -> handleSelection());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
|
||||
Bundle bundle = adapterItemWithPayload.getPayload();
|
||||
adapterItemWithPayload.setSelectionHandler(this::handleSelection);
|
||||
if (bundle.getString("package", "").equals(mPackageName)) {
|
||||
return;
|
||||
}
|
||||
mIsInstantGame = bundle.getBoolean("instant_game", false);
|
||||
mPackageName = bundle.getString("package");
|
||||
mPreviewButton.setVisibility(mIsInstantGame ? VISIBLE : GONE);
|
||||
mTitleView.setText(bundle.getString("title"));
|
||||
// TODO: Should use a generic type to get values b/165320033
|
||||
showIfNecessary(mDetailViews[0], bundle.getString("price"));
|
||||
showIfNecessary(mDetailViews[1], bundle.getString("rating"));
|
||||
showIfNecessary(mDetailViews[2], bundle.getString("category"));
|
||||
|
||||
mIconView.setBackgroundResource(R.drawable.ic_deepshortcut_placeholder);
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
try {
|
||||
// TODO: Handle caching
|
||||
URL url = new URL(bundle.getString("icon_url"));
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
|
||||
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
|
||||
Bitmap.createScaledBitmap(bitmap, mDeviceProfile.allAppsIconSizePx,
|
||||
mDeviceProfile.allAppsIconSizePx, false));
|
||||
mIconView.post(() -> mIconView.setBackground(bitmapDrawable));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showIfNecessary(TextView textView, @Nullable String string) {
|
||||
if (string == null || string.isEmpty()) {
|
||||
textView.setVisibility(GONE);
|
||||
} else {
|
||||
textView.setText(string);
|
||||
textView.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSelection() {
|
||||
if (mPackageName == null) return;
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(
|
||||
"https://play.google.com/store/apps/details?id="
|
||||
+ mPackageName));
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(i);
|
||||
}
|
||||
|
||||
private void launchInstantGame() {
|
||||
if (!mIsInstantGame) return;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
String referrer = "Pixel_Launcher";
|
||||
String id = mPackageName;
|
||||
String deepLinkUrl = "market://details?id=" + id + "&launch=true&referrer=" + referrer;
|
||||
intent.setPackage("com.android.vending");
|
||||
intent.setData(Uri.parse(deepLinkUrl));
|
||||
intent.putExtra("overlay", true);
|
||||
intent.putExtra("callerId", getContext().getPackageName());
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter;
|
||||
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
|
||||
|
||||
/**
|
||||
* Header text view that shows a title for a given section in All apps search
|
||||
*/
|
||||
public class SearchSectionHeaderView extends TextView implements
|
||||
AllAppsSearchBarController.PayloadResultHandler<String> {
|
||||
public SearchSectionHeaderView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SearchSectionHeaderView(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SearchSectionHeaderView(Context context, @Nullable AttributeSet attrs, int styleAttr) {
|
||||
super(context, attrs, styleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAdapterInfo(AllAppsGridAdapter.AdapterItemWithPayload<String> adapterItem) {
|
||||
String title = adapterItem.getPayload();
|
||||
if (title == null || !title.isEmpty()) {
|
||||
setText(title);
|
||||
setVisibility(VISIBLE);
|
||||
} else {
|
||||
setVisibility(INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user