Thumbnail/Suggest view type support remote action

Bug: 169330678


Change-Id: I629d3e6b1622bf71e0174eb2489e976ef98875ad
This commit is contained in:
Hyunyoung Song 2020-09-28 01:53:31 -07:00
parent 49876bbe7e
commit f271139682
5 changed files with 224 additions and 17 deletions

View File

@ -0,0 +1,38 @@
<?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.SearchResultSuggestRow 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:paddingStart="8dp"
android:layout_marginBottom="4dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" />
</com.android.launcher3.views.SearchResultSuggestRow>

View File

@ -98,6 +98,8 @@ public class AllAppsGridAdapter extends
public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13;
// 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;
@ -189,7 +191,8 @@ public class AllAppsGridAdapter extends
|| viewType == VIEW_TYPE_SEARCH_ROW
|| viewType == VIEW_TYPE_SEARCH_PEOPLE
|| viewType == VIEW_TYPE_SEARCH_THUMBNAIL
|| viewType == VIEW_TYPE_SEARCH_ICON_ROW;
|| viewType == VIEW_TYPE_SEARCH_ICON_ROW
|| viewType == VIEW_TYPE_SEARCH_SUGGEST;
}
}
@ -467,6 +470,9 @@ public class AllAppsGridAdapter extends
case VIEW_TYPE_SEARCH_THUMBNAIL:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_thumbnail, parent, false));
case VIEW_TYPE_SEARCH_SUGGEST:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_suggest, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@ -554,6 +560,7 @@ public class AllAppsGridAdapter extends
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_PEOPLE:
case VIEW_TYPE_SEARCH_THUMBNAIL:
case VIEW_TYPE_SEARCH_SUGGEST:
AdapterItemWithPayload item =
(AdapterItemWithPayload) mApps.getAdapterItems().get(position);
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;

View File

@ -0,0 +1,131 @@
/*
* 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 static com.android.systemui.plugins.shared.SearchTarget.ItemType.SUGGEST;
import android.content.Context;
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.AdapterItemWithPayload;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
/**
* A view representing a fallback search suggestion row.
*/
public class SearchResultSuggestRow extends LinearLayout implements
View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
private final Object[] mTargetInfo = createTargetInfo();
private AllAppsSearchPlugin mPlugin;
private AdapterItemWithPayload<SearchTarget> mAdapterItem;
private TextView mTitle;
public SearchResultSuggestRow(@NonNull Context context) {
super(context);
}
public SearchResultSuggestRow(@NonNull Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
}
public SearchResultSuggestRow(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTitle = findViewById(R.id.title);
setOnClickListener(this);
}
@Override
public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItemWithPayload) {
mAdapterItem = adapterItemWithPayload;
SearchTarget payload = adapterItemWithPayload.getPayload();
mPlugin = adapterItemWithPayload.getPlugin();
if (payload.mRemoteAction != null) {
RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(payload.mRemoteAction,
payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
setTag(itemInfo);
}
showIfAvailable(mTitle, payload.mRemoteAction.getTitle().toString());
setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
adapterItemWithPayload.setSelectionHandler(this::handleSelection);
}
@Override
public Object[] getTargetInfo() {
return mTargetInfo;
}
private void handleSelection(int eventType) {
ItemInfo itemInfo = (ItemInfo) getTag();
Launcher launcher = Launcher.getLauncher(getContext());
if (itemInfo instanceof RemoteActionItemInfo) return;
RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SUGGEST, eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START,
remoteItemInfo.shouldStartInLauncher());
searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
remoteItemInfo.getToken());
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
}
}
@Override
public void onClick(View view) {
handleSelection(SearchTargetEvent.SELECT);
}
private void showIfAvailable(TextView view, @Nullable String string) {
System.out.println("Plugin suggest string:" + string);
if (TextUtils.isEmpty(string)) {
view.setVisibility(GONE);
} else {
System.out.println("Plugin suggest string:" + string);
view.setVisibility(VISIBLE);
view.setText(string);
}
}
}

View File

@ -18,8 +18,8 @@ package com.android.launcher3.views;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
@ -28,6 +28,10 @@ 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.model.data.ItemInfo;
import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
@ -37,10 +41,9 @@ 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<Bundle> {
implements AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
private final Object[] mTargetInfo = createTargetInfo();
Intent mIntent;
AllAppsSearchPlugin mPlugin;
int mPosition;
@ -58,26 +61,48 @@ public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppComp
private void handleSelection(int eventType) {
Launcher launcher = Launcher.getLauncher(getContext());
launcher.startActivitySafely(this, mIntent, null);
SearchTargetEvent event = getSearchTargetEvent(
SearchTarget.ItemType.SCREENSHOT, eventType);
ItemInfo itemInfo = (ItemInfo) getTag();
if (itemInfo instanceof RemoteActionItemInfo) {
RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
} else {
ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
}
if (mPlugin != null) {
SearchTargetEvent event = getSearchTargetEvent(
SearchTarget.ItemType.SCREENSHOT, eventType);
mPlugin.notifySearchTargetEvent(event);
}
}
@Override
public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItem) {
public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItem) {
Launcher launcher = Launcher.getLauncher(getContext());
mPosition = adapterItem.position;
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null,
(Bitmap) adapterItem.getPayload().getParcelable("bitmap"));
SearchTarget target = adapterItem.getPayload();
Bitmap bitmap;
if (target.mRemoteAction != null) {
RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
ItemClickHandler.onClickRemoteAction(launcher, itemInfo);
bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
.loadDrawable(getContext())).getBitmap();
setTag(itemInfo);
} else {
bitmap = (Bitmap) target.bundle.getParcelable("bitmap");
WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
itemInfo.intent = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(target.bundle.getString("uri")))
.setType("image/*")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setTag(itemInfo);
}
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, 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);
setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
mPlugin = adapterItem.getPlugin();
adapterItem.setSelectionHandler(this::handleSelection);
}

View File

@ -80,7 +80,12 @@ public class SearchTarget implements Comparable<SearchTarget> {
* N number of 1x1 ratio thumbnail is rendered.
* (current N = 3)
*/
THUMBNAIL(8);
THUMBNAIL(8),
/**
* Fallback search icon and relevant text is rendered.
*/
SUGGEST(9);
private final int mId;
@ -102,7 +107,8 @@ public class SearchTarget implements Comparable<SearchTarget> {
SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
PEOPLE(6, "People", ViewType.PEOPLE),
SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL),
REMOTE_ACTION(8, "Remote Actions", ViewType.SHORTCUT);
REMOTE_ACTION(8, "Remote Actions", ViewType.SHORTCUT),
SUGGEST(9, "Fallback Search", ViewType.SUGGEST);
private final int mId;