diff --git a/res/layout/search_result_widget_preview.xml b/res/layout/search_result_widget_preview.xml new file mode 100644 index 0000000000..942b199b7f --- /dev/null +++ b/res/layout/search_result_widget_preview.xml @@ -0,0 +1,8 @@ + + + + + \ 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 d04935223b..3c88288160 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -92,6 +92,8 @@ public class AllAppsGridAdapter extends public static final int VIEW_TYPE_SEARCH_WIDGET_LIVE = 1 << 15; + public static final int VIEW_TYPE_SEARCH_WIDGET_PREVIEW = 1 << 16; + // 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 | VIEW_TYPE_SEARCH_ICON; @@ -287,7 +289,8 @@ public class AllAppsGridAdapter extends int viewType = mApps.getAdapterItems().get(position).viewType; if (isIconViewType(viewType)) { return 1 * SPAN_MULTIPLIER; - } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) { + } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL + || viewType == VIEW_TYPE_SEARCH_WIDGET_PREVIEW) { return mAppsPerRow; } else { // Section breaks span the full width @@ -433,6 +436,9 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_WIDGET_LIVE: return new ViewHolder(mLayoutInflater.inflate( R.layout.search_result_widget_live, parent, false)); + case VIEW_TYPE_SEARCH_WIDGET_PREVIEW: + return new ViewHolder(mLayoutInflater.inflate( + R.layout.search_result_widget_preview, parent, false)); default: throw new RuntimeException("Unexpected view type"); } @@ -476,6 +482,7 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_THUMBNAIL: case VIEW_TYPE_SEARCH_SUGGEST: case VIEW_TYPE_SEARCH_WIDGET_LIVE: + case VIEW_TYPE_SEARCH_WIDGET_PREVIEW: SearchAdapterItem item = (SearchAdapterItem) mApps.getAdapterItems().get(position); SearchTargetHandler payloadResultView = (SearchTargetHandler) holder.itemView; diff --git a/src/com/android/launcher3/views/SearchResultWidgetPreview.java b/src/com/android/launcher3/views/SearchResultWidgetPreview.java new file mode 100644 index 0000000000..c11c232307 --- /dev/null +++ b/src/com/android/launcher3/views/SearchResultWidgetPreview.java @@ -0,0 +1,141 @@ +/* + * 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.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.graphics.Point; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.Toast; + +import androidx.annotation.Nullable; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; +import com.android.launcher3.allapps.search.AllAppsSearchBarController; +import com.android.launcher3.allapps.search.SearchEventTracker; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.model.WidgetItem; +import com.android.launcher3.touch.ItemLongClickListener; +import com.android.launcher3.widget.BaseWidgetSheet; +import com.android.launcher3.widget.PendingItemDragHelper; +import com.android.launcher3.widget.WidgetCell; +import com.android.launcher3.widget.WidgetImageView; +import com.android.systemui.plugins.shared.SearchTarget; +import com.android.systemui.plugins.shared.SearchTargetEvent; + +/** + * displays preview of a widget upon receiving {@link AppWidgetProviderInfo} from Search provider + */ +public class SearchResultWidgetPreview extends LinearLayout implements + AllAppsSearchBarController.SearchTargetHandler, View.OnLongClickListener, + View.OnClickListener { + + public static final String TARGET_TYPE_WIDGET_PREVIEW = "widget_preview"; + private final Launcher mLauncher; + private final LauncherAppState mAppState; + private WidgetCell mWidgetCell; + private Toast mWidgetToast; + + private SearchTarget mSearchTarget; + + + public SearchResultWidgetPreview(Context context) { + this(context, null, 0); + } + + public SearchResultWidgetPreview(Context context, + @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public SearchResultWidgetPreview(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + mLauncher = Launcher.getLauncher(context); + mAppState = LauncherAppState.getInstance(context); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mWidgetCell = findViewById(R.id.widget_cell); + mWidgetCell.setOnLongClickListener(this); + mWidgetCell.setOnClickListener(this); + } + + @Override + public void applySearchTarget(SearchTarget searchTarget) { + if (searchTarget.getExtras() == null + || searchTarget.getExtras().getParcelable("provider") == null) { + setVisibility(GONE); + return; + } + mSearchTarget = searchTarget; + AppWidgetProviderInfo providerInfo = searchTarget.getExtras().getParcelable("provider"); + LauncherAppWidgetProviderInfo pInfo = LauncherAppWidgetProviderInfo.fromProviderInfo( + getContext(), providerInfo); + MODEL_EXECUTOR.post(() -> { + WidgetItem widgetItem = new WidgetItem(pInfo, mLauncher.getDeviceProfile().inv, + mAppState.getIconCache()); + MAIN_EXECUTOR.post(() -> { + mWidgetCell.applyFromCellItem(widgetItem, mAppState.getWidgetCache()); + mWidgetCell.ensurePreview(); + }); + }); + + } + + @Override + public boolean onLongClick(View view) { + view.cancelLongPress(); + if (!ItemLongClickListener.canStartDrag(mLauncher)) return false; + if (mWidgetCell.getTag() == null) return false; + + WidgetImageView imageView = mWidgetCell.getWidgetView(); + if (imageView.getBitmap() == null) { + return false; + } + + int[] loc = new int[2]; + mLauncher.getDragLayer().getLocationInDragLayer(imageView, loc); + + new PendingItemDragHelper(mWidgetCell).startDrag( + imageView.getBitmapBounds(), imageView.getBitmap().getWidth(), imageView.getWidth(), + new Point(loc[0], loc[1]), mLauncher.getAppsView(), new DragOptions()); + handleSelection(SearchTargetEvent.LONG_PRESS); + return true; + } + + @Override + public void onClick(View view) { + mWidgetToast = BaseWidgetSheet.showWidgetToast(getContext(), mWidgetToast); + handleSelection(SearchTargetEvent.SELECT); + } + + @Override + public void handleSelection(int eventType) { + SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent( + new SearchTargetEvent.Builder(mSearchTarget, eventType).build()); + } +} diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index 01af96cb33..a38e90dfd8 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -42,7 +42,7 @@ import com.android.launcher3.views.AbstractSlideInView; /** * Base class for various widgets popup */ -abstract class BaseWidgetSheet extends AbstractSlideInView +public abstract class BaseWidgetSheet extends AbstractSlideInView implements OnClickListener, OnLongClickListener, DragSource, PopupDataProvider.PopupDataChangeListener { @@ -74,16 +74,7 @@ abstract class BaseWidgetSheet extends AbstractSlideInView @Override public final void onClick(View v) { - // Let the user know that they have to long press to add a widget - if (mWidgetInstructionToast != null) { - mWidgetInstructionToast.cancel(); - } - - CharSequence msg = Utilities.wrapForTts( - getContext().getText(R.string.long_press_widget_to_add), - getContext().getString(R.string.long_accessible_way_to_add)); - mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT); - mWidgetInstructionToast.show(); + mWidgetInstructionToast = showWidgetToast(getContext(), mWidgetInstructionToast); } @Override @@ -146,4 +137,21 @@ abstract class BaseWidgetSheet extends AbstractSlideInView protected SystemUiController getSystemUiController() { return mLauncher.getSystemUiController(); } + + /** + * Show Widget tap toast prompting user to drag instead + */ + public static Toast showWidgetToast(Context context, Toast toast) { + // Let the user know that they have to long press to add a widget + if (toast != null) { + toast.cancel(); + } + + CharSequence msg = Utilities.wrapForTts( + context.getText(R.string.long_press_widget_to_add), + context.getString(R.string.long_accessible_way_to_add)); + toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT); + toast.show(); + return toast; + } }