From bdf4f7129919467e79beb25daaa41879b9622fd5 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Wed, 13 Jan 2021 11:05:12 -0600 Subject: [PATCH] Migrate from Plugin SearchTarget to API search Target [3/3] - Implement SearchServicePipeline which utilizes system Search services for AllAppsSearch Results - Parse android.app.search.SearchTarget handling for Shortcut, Slice, Settings and Play results - Aggregate SearchTargets to a tree structure for in-line Search Results Bug: 177223401 Test: Manual Change-Id: Iddc0f3691578fd332cd2df643a237b29f3eccd0d --- .../search/DeviceSearchAdapterProvider.java | 27 +++- .../launcher3/search/SearchAdapterItem.java | 7 + .../launcher3/search/SearchResultIcon.java | 30 +++- .../launcher3/search/SearchResultIconRow.java | 12 ++ .../search/SearchResultPlayItem.java | 142 +++++++----------- .../search/SearchResultSettingsSlice.java | 15 ++ .../search/SearchSectionHeaderView.java | 9 ++ .../search/SearchServicePipeline.java | 137 +++++++++++++++++ .../search/SearchSettingsRowView.java | 10 ++ .../launcher3/search/SearchTargetHandler.java | 9 +- .../uioverrides/QuickstepLauncher.java | 1 + .../launcher3/allapps/SearchUiManager.java | 5 + .../launcher3/config/FeatureFlags.java | 5 +- 13 files changed, 309 insertions(+), 100 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/search/SearchServicePipeline.java diff --git a/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java b/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java index 9ce196ef84..3343cf5d69 100644 --- a/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java +++ b/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java @@ -23,6 +23,8 @@ import android.util.SparseIntArray; import android.view.LayoutInflater; import android.view.ViewGroup; +import com.android.app.search.LayoutType; +import com.android.app.search.ResultType; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsContainerView; @@ -78,10 +80,10 @@ public class DeviceSearchAdapterProvider extends SearchAdapterProvider { SearchTargetHandler payloadResultView = (SearchTargetHandler) holder.itemView; - if (FeatureFlags.SEARCH_TARGET_LEGACY.get()) { + if (!FeatureFlags.USE_SEARCH_API.get()) { payloadResultView.applySearchTarget(item.getSearchTargetLegacy()); } else { - payloadResultView.applySearchTarget(item.getSearchTarget()); + payloadResultView.applySearchTarget(item.getSearchTarget(), item.getInlineItems()); } } @@ -123,9 +125,24 @@ public class DeviceSearchAdapterProvider extends SearchAdapterProvider { * Returns -1 if viewType is not found */ public int getViewTypeForSearchTarget(SearchTarget t) { - //TODO: Replace with values from :SearchUi - if (t.getResultType() == 1 && t.getLayoutType().equals("icon")) { - return VIEW_TYPE_SEARCH_ICON; + if (t.getLayoutType().equals(LayoutType.TEXT_HEADER)) { + return VIEW_TYPE_SEARCH_CORPUS_TITLE; + } + switch (t.getResultType()) { + case ResultType.APPLICATION: + if (t.getLayoutType().equals(LayoutType.ICON_SINGLE_VERTICAL_TEXT)) { + return VIEW_TYPE_SEARCH_ICON; + } + break; + case ResultType.SETTING: + if (t.getLayoutType().equals(LayoutType.ICON_SLICE)) { + return VIEW_TYPE_SEARCH_SLICE; + } + return VIEW_TYPE_SEARCH_ROW; + case ResultType.SHORTCUT: + return VIEW_TYPE_SEARCH_ICON_ROW; + case ResultType.PLAY: + return VIEW_TYPE_SEARCH_ROW_WITH_BUTTON; } return -1; } diff --git a/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java b/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java index 258d97750b..65ac3f9ceb 100644 --- a/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java +++ b/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java @@ -32,12 +32,16 @@ import android.app.search.SearchTarget; import com.android.launcher3.allapps.AllAppsGridAdapter; import com.android.systemui.plugins.shared.SearchTargetLegacy; +import java.util.ArrayList; +import java.util.List; + /** * Extension of AdapterItem that contains an extra payload specific to item */ public class SearchAdapterItem extends AllAppsGridAdapter.AdapterItem { private SearchTargetLegacy mSearchTargetLegacy; private SearchTarget mSearchTarget; + private List mInlineItems = new ArrayList<>(); private static final int AVAILABLE_FOR_ACCESSIBILITY = VIEW_TYPE_SEARCH_ROW_WITH_BUTTON @@ -65,6 +69,9 @@ public class SearchAdapterItem extends AllAppsGridAdapter.AdapterItem { return mSearchTarget; } + public List getInlineItems() { + return mInlineItems; + } @Override protected boolean isCountedForAccessibility() { return (AVAILABLE_FOR_ACCESSIBILITY & viewType) == viewType; diff --git a/quickstep/src/com/android/launcher3/search/SearchResultIcon.java b/quickstep/src/com/android/launcher3/search/SearchResultIcon.java index e4d737c44f..d5fe0e8456 100644 --- a/quickstep/src/com/android/launcher3/search/SearchResultIcon.java +++ b/quickstep/src/com/android/launcher3/search/SearchResultIcon.java @@ -31,10 +31,12 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import com.android.app.search.ResultType; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.allapps.AllAppsStore; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.data.AppInfo; @@ -46,6 +48,7 @@ import com.android.launcher3.util.ComponentKey; import com.android.systemui.plugins.shared.SearchTargetEventLegacy; import com.android.systemui.plugins.shared.SearchTargetLegacy; +import java.util.List; import java.util.function.Consumer; /** @@ -128,10 +131,27 @@ public class SearchResultIcon extends BubbleTextView implements } } + /** + * Applies {@link SearchTarget} to view. registers a consumer after a corresponding + * {@link ItemInfoWithIcon} is created + */ + public void applySearchTarget(SearchTarget searchTarget, List inlineItems, + Consumer cb) { + mOnItemInfoChanged = cb; + applySearchTarget(searchTarget, inlineItems); + } + @Override - public void applySearchTarget(SearchTarget searchTarget) { - prepareUsingApp(new ComponentName(searchTarget.getPackageName(), - searchTarget.getExtras().getString("class")), searchTarget.getUserHandle()); + public void applySearchTarget(SearchTarget parentTarget, List children) { + switch (parentTarget.getResultType()) { + case ResultType.APPLICATION: + prepareUsingApp(new ComponentName(parentTarget.getPackageName(), + parentTarget.getExtras().getString("class")), parentTarget.getUserHandle()); + break; + case ResultType.SHORTCUT: + prepareUsingShortcutInfo(parentTarget.getShortcutInfo()); + break; + } } private void prepareUsingApp(ComponentName componentName, UserHandle userHandle) { @@ -185,7 +205,9 @@ public class SearchResultIcon extends BubbleTextView implements @Override public void handleSelection(int eventType) { mLauncher.getItemOnClickListener().onClick(this); - reportEvent(eventType); + if (!FeatureFlags.USE_SEARCH_API.get()) { + reportEvent(eventType); + } } private void reportEvent(int eventType) { diff --git a/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java b/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java index 8c491d27d1..80d543a23c 100644 --- a/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java +++ b/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java @@ -18,6 +18,7 @@ package com.android.launcher3.search; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.app.search.SearchTarget; import android.content.ComponentName; import android.content.Context; import android.content.pm.ShortcutInfo; @@ -32,6 +33,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import com.android.app.search.ResultType; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; @@ -111,6 +113,16 @@ public class SearchResultIconRow extends LinearLayout implements setOnLongClickListener(this); } + @Override + public void applySearchTarget(SearchTarget parentTarget, List children) { + mResultIcon.applySearchTarget(parentTarget, children, this); + if (parentTarget.getResultType() == ResultType.SHORTCUT) { + ShortcutInfo shortcutInfo = parentTarget.getShortcutInfo(); + setProviderDetails(new ComponentName(shortcutInfo.getPackage(), ""), + shortcutInfo.getUserHandle()); + } + } + @Override public void applySearchTarget(SearchTargetLegacy searchTarget) { mSearchTarget = searchTarget; diff --git a/quickstep/src/com/android/launcher3/search/SearchResultPlayItem.java b/quickstep/src/com/android/launcher3/search/SearchResultPlayItem.java index 3bb821f958..840bde9952 100644 --- a/quickstep/src/com/android/launcher3/search/SearchResultPlayItem.java +++ b/quickstep/src/com/android/launcher3/search/SearchResultPlayItem.java @@ -17,6 +17,8 @@ package com.android.launcher3.search; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import android.app.search.SearchAction; +import android.app.search.SearchTarget; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -27,8 +29,6 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; 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; @@ -43,12 +43,11 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.icons.BitmapRenderer; import com.android.launcher3.util.Themes; -import com.android.systemui.plugins.shared.SearchTargetEventLegacy; -import com.android.systemui.plugins.shared.SearchTargetLegacy; import java.io.IOException; import java.net.URL; import java.net.URLConnection; +import java.util.List; /** * A View representing a PlayStore item. @@ -67,9 +66,8 @@ public class SearchResultPlayItem extends LinearLayout implements private TextView[] mDetailViews = new TextView[3]; private Button mPreviewButton; private String mPackageName; - private boolean mIsInstantGame; - - private SearchTargetLegacy mSearchTarget; + private Intent mIntent; + private Intent mSecondaryIntent; public SearchResultPlayItem(Context context) { @@ -93,7 +91,7 @@ public class SearchResultPlayItem extends LinearLayout implements mIconView = findViewById(R.id.icon); mTitleView = findViewById(R.id.title_view); mPreviewButton = findViewById(R.id.try_button); - mPreviewButton.setOnClickListener(view -> launchInstantGame()); + mPreviewButton.setOnClickListener(view -> launchIntent(mSecondaryIntent)); mDetailViews[0] = findViewById(R.id.detail_0); mDetailViews[1] = findViewById(R.id.detail_1); mDetailViews[2] = findViewById(R.id.detail_2); @@ -101,9 +99,59 @@ public class SearchResultPlayItem extends LinearLayout implements ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams(); iconParams.height = mDeviceProfile.allAppsIconSizePx; iconParams.width = mDeviceProfile.allAppsIconSizePx; - setOnClickListener(view -> handleSelection(SearchTargetEventLegacy.SELECT)); + setOnClickListener(view -> launchIntent(mIntent)); } + 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 launchIntent(Intent intent) { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getContext().startActivity(intent); + } + + @Override + public void applySearchTarget(SearchTarget parentTarget, List children) { + if (parentTarget.getPackageName().equals(mPackageName)) { + return; + } + mPackageName = parentTarget.getPackageName(); + SearchAction action = parentTarget.getSearchAction(); + mTitleView.setText(action.getTitle()); + showIfNecessary(mDetailViews[0], action.getSubtitle().toString()); + mIntent = action.getIntent(); + + mIconView.setBackgroundResource(R.drawable.ic_deepshortcut_placeholder); + loadIcon(action.getIcon().getUri().toString()); + + mSecondaryIntent = children.size() == 1 ? children.get(0).getSearchAction().getIntent() + : null; + mPreviewButton.setVisibility(mSecondaryIntent == null ? GONE : VISIBLE); + } + + private void loadIcon(String iconUrl) { + UI_HELPER_EXECUTOR.execute(() -> { + try { + URL url = new URL(iconUrl); + URLConnection con = url.openConnection(); + con.addRequestProperty("Cache-Control", "max-age: 0"); + con.setUseCaches(true); + Bitmap bitmap = BitmapFactory.decodeStream(con.getInputStream()); + BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), getRoundedBitmap( + Bitmap.createScaledBitmap(bitmap, mDeviceProfile.allAppsIconSizePx, + mDeviceProfile.allAppsIconSizePx, false))); + mIconView.post(() -> mIconView.setBackground(bitmapDrawable)); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } private Bitmap getRoundedBitmap(Bitmap bitmap) { final int iconSize = bitmap.getWidth(); @@ -124,80 +172,4 @@ public class SearchResultPlayItem extends LinearLayout implements }); return output; } - - - @Override - public void applySearchTarget(SearchTargetLegacy searchTarget) { - mSearchTarget = searchTarget; - Bundle bundle = searchTarget.getExtras(); - SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this); - 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")); - - mIconView.setBackgroundResource(R.drawable.ic_deepshortcut_placeholder); - UI_HELPER_EXECUTOR.execute(() -> { - try { - URL url = new URL(bundle.getString("icon_url")); - URLConnection con = url.openConnection(); -// TODO: monitor memory and investigate if it's better to use glide - con.addRequestProperty("Cache-Control", "max-age: 0"); - con.setUseCaches(true); - Bitmap bitmap = BitmapFactory.decodeStream(con.getInputStream()); - BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), getRoundedBitmap( - 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); - } - } - - @Override - public void handleSelection(int eventType) { - 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); - logSearchEvent(eventType); - } - - 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); - logSearchEvent(SearchTargetEventLegacy.CHILD_SELECT); - } - - private void logSearchEvent(int eventType) { - SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent( - new SearchTargetEventLegacy.Builder(mSearchTarget, eventType).build()); - } } diff --git a/quickstep/src/com/android/launcher3/search/SearchResultSettingsSlice.java b/quickstep/src/com/android/launcher3/search/SearchResultSettingsSlice.java index 80ad305af8..bf50b67491 100644 --- a/quickstep/src/com/android/launcher3/search/SearchResultSettingsSlice.java +++ b/quickstep/src/com/android/launcher3/search/SearchResultSettingsSlice.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.search; +import android.app.search.SearchTarget; import android.content.Context; import android.net.Uri; import android.util.AttributeSet; @@ -35,6 +36,8 @@ import com.android.launcher3.R; import com.android.systemui.plugins.shared.SearchTargetEventLegacy; import com.android.systemui.plugins.shared.SearchTargetLegacy; +import java.util.List; + /** * A slice view wrapper with settings app icon at start */ @@ -88,6 +91,18 @@ public class SearchResultSettingsSlice extends LinearLayout implements } } + @Override + public void applySearchTarget(SearchTarget parentTarget, List children) { + reset(); + try { + mSliceLiveData = mLauncher.getLiveSearchManager().getSliceForUri( + parentTarget.getSliceUri()); + mSliceLiveData.observe(mLauncher, mSliceView); + } catch (Exception ex) { + Log.e(TAG, "unable to bind slice", ex); + } + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java b/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java index eb40938ecf..ccc38dbbbd 100644 --- a/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java +++ b/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.search; +import android.app.search.SearchTarget; import android.content.Context; import android.util.AttributeSet; import android.widget.TextView; @@ -23,6 +24,8 @@ import androidx.annotation.Nullable; import com.android.systemui.plugins.shared.SearchTargetLegacy; +import java.util.List; + /** * Header text view that shows a title for a given section in All apps search */ @@ -53,4 +56,10 @@ public class SearchSectionHeaderView extends TextView implements setVisibility(INVISIBLE); } } + + @Override + public void applySearchTarget(SearchTarget parentTarget, List children) { + setText(parentTarget.getSearchAction().getTitle()); + setVisibility(VISIBLE); + } } diff --git a/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java b/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java new file mode 100644 index 0000000000..6585213b65 --- /dev/null +++ b/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java @@ -0,0 +1,137 @@ +/* + * 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.search; + +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; + +import android.app.search.Query; +import android.app.search.SearchContext; +import android.app.search.SearchSession; +import android.app.search.SearchTarget; +import android.app.search.SearchUiManager; +import android.content.Context; +import android.os.CancellationSignal; +import android.text.TextUtils; +import android.util.Log; + +import com.android.app.search.ResultType; +import com.android.launcher3.allapps.AllAppsGridAdapter; +import com.android.launcher3.allapps.AllAppsSectionDecorator; +import com.android.launcher3.allapps.search.SearchPipeline; +import com.android.launcher3.allapps.search.SearchSectionInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.function.Consumer; + +/** + * Search pipeline utilizing {@link android.app.search.SearchUiManager} + */ +public class SearchServicePipeline implements SearchPipeline { + private static final int SUPPORTED_RESULT_TYPES = + ResultType.APPLICATION | ResultType.SHORTCUT | ResultType.PLAY | ResultType.PEOPLE + | ResultType.SETTING; + private static final int REQUEST_TIMEOUT = 200; + private static final String TAG = "SearchServicePipeline"; + + + private final Context mContext; + private final SearchSession mSession; + private final DeviceSearchAdapterProvider mAdapterProvider; + + private boolean mCanceled = false; + + + public SearchServicePipeline(Context context, DeviceSearchAdapterProvider adapterProvider) { + mContext = context; + mAdapterProvider = adapterProvider; + SearchUiManager manager = context.getSystemService(SearchUiManager.class); + mSession = manager.createSearchSession( + new SearchContext(SUPPORTED_RESULT_TYPES, REQUEST_TIMEOUT, null)); + } + + @Override + public void query(String input, Consumer> callback, + CancellationSignal cancellationSignal) { + mCanceled = false; + Query query = new Query(input, System.currentTimeMillis(), null); + mSession.query(query, UI_HELPER_EXECUTOR, items -> { + if (!mCanceled) { + callback.accept(this.onResult(items)); + } + Log.w(TAG, "Ignoring results due to cancel signal"); + }); + } + + /** + * Given A list of search Targets, pairs a group of search targets to a AdapterItem that can + * be inflated in AllAppsRecyclerView + */ + private ArrayList onResult(List searchTargets) { + HashMap adapterMap = new LinkedHashMap<>(); + List unmappedChildren = new ArrayList<>(); + SearchSectionInfo section = new SearchSectionInfo(); + section.setDecorationHandler( + new AllAppsSectionDecorator.SectionDecorationHandler(mContext, true)); + for (SearchTarget target : searchTargets) { + if (!TextUtils.isEmpty(target.getParentId())) { + if (!addChildToParent(target, adapterMap)) { + unmappedChildren.add(target); + } + continue; + } + int viewType = mAdapterProvider.getViewTypeForSearchTarget(target); + if (viewType != -1) { + SearchAdapterItem adapterItem = new SearchAdapterItem(target, viewType); + adapterItem.searchSectionInfo = section; + adapterMap.put(target.getId(), adapterItem); + } + } + for (SearchTarget s : unmappedChildren) { + if (!addChildToParent(s, adapterMap)) { + Log.w(TAG, + "Unable to pair child " + s.getId() + " to parent " + s.getParentId()); + } + } + return new ArrayList<>(adapterMap.values()); + } + + /** + * Adds a child SearchTarget to a collection of searchTarget children with a shared parentId. + * Returns false if no parent searchTarget with id=$parentId does not exists. + */ + private boolean addChildToParent(SearchTarget target, HashMap map) { + if (!map.containsKey(target.getParentId())) return false; + map.get(target.getParentId()).getInlineItems().add(target); + return true; + } + + /** + * Unregister callbacks and destroy search session + */ + public void destroy() { + mSession.destroy(); + } + + /** + * Cancels current ongoing search request. + */ + public void cancel() { + mCanceled = true; + } +} diff --git a/quickstep/src/com/android/launcher3/search/SearchSettingsRowView.java b/quickstep/src/com/android/launcher3/search/SearchSettingsRowView.java index 8306e3b555..6fc0046b12 100644 --- a/quickstep/src/com/android/launcher3/search/SearchSettingsRowView.java +++ b/quickstep/src/com/android/launcher3/search/SearchSettingsRowView.java @@ -19,6 +19,8 @@ import static com.android.launcher3.FastBitmapDrawable.newIcon; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.app.search.SearchAction; +import android.app.search.SearchTarget; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -97,6 +99,14 @@ public class SearchSettingsRowView extends LinearLayout implements SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this); } + @Override + public void applySearchTarget(SearchTarget parentTarget, List children) { + SearchAction action = parentTarget.getSearchAction(); + mIconView.setContentDescription(action.getTitle()); + showIfAvailable(mTitleView, action.getTitle().toString()); + showIfAvailable(mBreadcrumbsView, action.getSubtitle().toString()); + } + private void showIfAvailable(TextView view, @Nullable String string) { if (TextUtils.isEmpty(string)) { view.setVisibility(GONE); diff --git a/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java b/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java index 9ff057f0bf..e72578dcd3 100644 --- a/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java +++ b/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java @@ -20,6 +20,8 @@ import android.app.search.SearchTarget; import com.android.systemui.plugins.shared.SearchTargetLegacy; +import java.util.List; + /** * An interface for supporting dynamic search results */ @@ -28,13 +30,14 @@ public interface SearchTargetHandler { /** * Update view using values from {@link SearchTargetLegacy} */ - void applySearchTarget(SearchTargetLegacy searchTarget); + default void applySearchTarget(SearchTargetLegacy searchTarget) { + } + /** * Update view using values from {@link SearchTargetLegacy} */ - default void applySearchTarget(SearchTarget searchTarget){ - + default void applySearchTarget(SearchTarget parentTarget, List children) { } /** diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 3be1ced810..4f62d2face 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -220,6 +220,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void onDestroy() { super.onDestroy(); + getAppsView().getSearchUiManager().destroy(); if (mHotseatPredictionController != null) { mHotseatPredictionController.destroy(); mHotseatPredictionController = null; diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index aa056a01f4..f9260868f5 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -58,6 +58,11 @@ public interface SearchUiManager { void setContentVisibility(int visibleElements, PropertySetter setter, Interpolator interpolator); + /** + * Called when activity is destroyed. Used to close search system services + */ + default void destroy(){} + /** * Returns true if the QSB should be visible for the given set of visible elements */ diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 2455706d7d..81174d814d 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -98,9 +98,8 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_DEVICE_SEARCH = getDebugFlag( "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps"); - public static final BooleanFlag SEARCH_TARGET_LEGACY = getDebugFlag( - "SEARCH_TARGET_LEGACY", true, - "Use SearchTarget provided by plugin lib (only during migration)"); + public static final BooleanFlag USE_SEARCH_API = getDebugFlag( + "USE_SEARCH_API", true, "Use SearchUIManager api for device search"); public static final BooleanFlag DISABLE_INITIAL_IME_IN_ALLAPPS = getDebugFlag( "DISABLE_INITIAL_IME_IN_ALLAPPS", false, "Disable default IME state in all apps");