diff --git a/res/layout/search_result_thumbnail.xml b/res/layout/search_result_thumbnail.xml new file mode 100644 index 0000000000..0cc5a29f60 --- /dev/null +++ b/res/layout/search_result_thumbnail.xml @@ -0,0 +1,19 @@ + + + \ 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 d1340faf23..e08bd5ba3b 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -96,6 +96,8 @@ public class AllAppsGridAdapter extends public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11; + public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12; + // 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; @@ -186,6 +188,7 @@ public class AllAppsGridAdapter extends || viewType == VIEW_TYPE_SEARCH_SLICE || viewType == VIEW_TYPE_SEARCH_ROW || viewType == VIEW_TYPE_SEARCH_PEOPLE + || viewType == VIEW_TYPE_SEARCH_THUMBNAIL || viewType == VIEW_TYPE_SEARCH_SHORTCUT; } } @@ -307,15 +310,21 @@ public class AllAppsGridAdapter extends @Override public int getSpanSize(int position) { - if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) { - return 1; + int viewType = mApps.getAdapterItems().get(position).viewType; + if (isIconViewType(viewType)) { + return 1 * SPAN_MULTIPLIER; + } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) { + return mAppsPerRow; } else { // Section breaks span the full width - return mAppsPerRow; + return mAppsPerRow * SPAN_MULTIPLIER; } } } + // multiplier to support adapter item column count that is not mAppsPerRow. + private static final int SPAN_MULTIPLIER = 3; + private final BaseDraggingActivity mLauncher; private final LayoutInflater mLayoutInflater; private final AlphabeticalAppsList mApps; @@ -352,7 +361,7 @@ public class AllAppsGridAdapter extends public void setAppsPerRow(int appsPerRow) { mAppsPerRow = appsPerRow; - mGridLayoutMgr.setSpanCount(mAppsPerRow); + mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER); } /** @@ -444,6 +453,9 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_PEOPLE: return new ViewHolder(mLayoutInflater.inflate( R.layout.search_result_people_item, parent, false)); + case VIEW_TYPE_SEARCH_THUMBNAIL: + return new ViewHolder(mLayoutInflater.inflate( + R.layout.search_result_thumbnail, parent, false)); default: throw new RuntimeException("Unexpected view type"); } @@ -525,6 +537,7 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_ROW: case VIEW_TYPE_SEARCH_SHORTCUT: case VIEW_TYPE_SEARCH_PEOPLE: + case VIEW_TYPE_SEARCH_THUMBNAIL: PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView; payloadResultView.applyAdapterInfo( (AdapterItemWithPayload) mApps.getAdapterItems().get(position)); @@ -553,7 +566,6 @@ public class AllAppsGridAdapter extends } } - @Override public boolean onFailedToRecycleView(ViewHolder holder) { // Always recycle and we will reset the view when it is bound diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java new file mode 100644 index 0000000000..decc861565 --- /dev/null +++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java @@ -0,0 +1,81 @@ +/* + * 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.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.util.AttributeSet; + +import androidx.core.graphics.drawable.RoundedBitmapDrawable; +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; + +import com.android.launcher3.Launcher; +import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; +import com.android.launcher3.allapps.search.AllAppsSearchBarController; +import com.android.launcher3.util.Themes; +import com.android.systemui.plugins.AllAppsSearchPlugin; +import com.android.systemui.plugins.shared.SearchTarget; +import com.android.systemui.plugins.shared.SearchTargetEvent; + +/** + * A view representing a high confidence app search result that includes shortcuts + */ +public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView + implements AllAppsSearchBarController.PayloadResultHandler { + + Intent mIntent; + AllAppsSearchPlugin mPlugin; + + public ThumbnailSearchResultView(Context context) { + super(context); + } + + public ThumbnailSearchResultView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ThumbnailSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + private void handleSelection(int eventType) { + Launcher launcher = Launcher.getLauncher(getContext()); + launcher.startActivitySafely(this, mIntent, null); + + SearchTargetEvent event = new SearchTargetEvent( + SearchTarget.ItemType.SCREENSHOT, eventType); + if (mPlugin != null) { + mPlugin.notifySearchTargetEvent(event); + } + } + + @Override + public void applyAdapterInfo(AdapterItemWithPayload adapterItem) { + RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, + (Bitmap) adapterItem.getPayload().getParcelable("bitmap")); + drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext())); + setImageDrawable(drawable); + mIntent = new Intent(Intent.ACTION_VIEW) + .setData(Uri.parse(adapterItem.getPayload().getString("uri"))) + .setType("image/*") + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mPlugin = adapterItem.getPlugin(); + adapterItem.setSelectionHandler(this::handleSelection); + } +} diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java index c6b8300499..9144976f98 100644 --- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java +++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java @@ -26,14 +26,52 @@ import java.util.List; public class SearchTarget implements Comparable { public enum ViewType { + + /** + * Consists of N number of icons. (N: launcher column count) + */ TOP_HIT(0), + + /** + * Consists of 1 icon and two subsidiary icons. + */ HERO(1), + + /** + * Main/sub/breadcrumb texts are rendered. + */ DETAIL(2), + + /** + * Consists of an icon, three detail strings. + */ ROW(3), + + /** + * Consists of an icon, three detail strings and a button. + */ ROW_WITH_BUTTON(4), + + /** + * Consists of a single slice view + */ SLICE(5), + + /** + * Similar to hero section. + */ SHORTCUT(6), - PEOPLE(7); + + /** + * Person icon and handling app icons are rendered. + */ + PEOPLE(7), + + /** + * N number of 1x1 ratio thumbnail is rendered. + * (current N = 3) + */ + THUMBNAIL(8); private final int mId; ViewType(int id) { @@ -52,9 +90,12 @@ public class SearchTarget implements Comparable { APP(3, "", ViewType.TOP_HIT), APP_HERO(4, "", ViewType.HERO), SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT), - PEOPLE(6, "People", ViewType.PEOPLE); + PEOPLE(6, "People", ViewType.PEOPLE), + SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL); private final int mId; + + /** Used to render section title. */ private final String mTitle; private final ViewType mViewType;