Merge "Show resize frame when widget is added." into sc-dev
diff --git a/res/drawable/full_rounded_transparent_ripple.xml b/res/drawable/full_rounded_transparent_ripple.xml
new file mode 100644
index 0000000..a1e7943
--- /dev/null
+++ b/res/drawable/full_rounded_transparent_ripple.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<ripple
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <shape android:shape="oval">
+            <size android:height="24dp" android:width="24dp"/>
+            <solid android:color="@android:color/white"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml
index 0b354e8..cb27f4f 100644
--- a/res/layout/widgets_search_bar.xml
+++ b/res/layout/widgets_search_bar.xml
@@ -31,11 +31,9 @@
         android:id="@+id/widgets_search_cancel_button"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:paddingVertical="12dp"
-        android:paddingStart="8dp"
-        android:paddingEnd="12dp"
+        android:padding="12dp"
         android:src="@drawable/ic_gm_close_24"
-        android:background="?android:selectableItemBackground"
+        android:background="@drawable/full_rounded_transparent_ripple"
         android:layout_gravity="center"
         android:contentDescription="@string/widgets_full_sheet_cancel_button_description"
         android:visibility="gone"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4f4a389..ddd838d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -55,6 +55,9 @@
     <string name="widget_dims_format">%1$d \u00d7 %2$d</string>
     <!-- Accessibility spoken message format for the dimensions of a widget in the drawer -->
     <string name="widget_accessible_dims_format">%1$d wide by %2$d high</string>
+    <!-- Spoken text for a screen reader. The placeholder text is the widget name.
+         [CHAR_LIMIT=none]-->
+    <string name="widget_preview_context_description"><xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
     <!-- Message to tell the user to press and hold a widget/icon to add it to the home screen.
          [CHAR LIMIT=NONE]  -->
     <string name="add_item_request_drag_hint">Touch &amp; hold the widget to move it around the Home screen</string>
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index c395d6c..40bc9c3 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -36,7 +36,7 @@
     public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
     public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
     public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
-    public static final String SEARCH_EDU_SEEN = "launcher.search_edu";
+    public static final String SEARCH_EDU_SEEN = "launcher.search_edu_seen";
     public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
 
     /**
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 3bf993e..9f0b9d9 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -24,11 +24,14 @@
 import android.view.View.OnLongClickListener;
 import android.widget.Toast;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.Nullable;
 import androidx.core.view.ViewCompat;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -47,10 +50,11 @@
  */
 public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
         implements OnClickListener, OnLongClickListener, DragSource,
-        PopupDataProvider.PopupDataChangeListener {
+        PopupDataProvider.PopupDataChangeListener, Insettable {
 
     protected static final String KEY_WIDGETS_EDUCATION_TIP_SEEN =
             "launcher.widgets_education_tip_seen";
+    protected final Rect mInsets = new Rect();
 
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
@@ -105,6 +109,35 @@
         return true;
     }
 
+    @Override
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
+
+    /**
+     * Measures the dimension of this view and its children by taking system insets, navigation bar,
+     * status bar, into account.
+     */
+    @GuardedBy("MainThread")
+    protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        int widthUsed;
+        if (mInsets.bottom > 0) {
+            widthUsed = mInsets.left + mInsets.right;
+        } else {
+            Rect padding = deviceProfile.workspacePadding;
+            widthUsed = Math.max(padding.left + padding.right,
+                    2 * (mInsets.left + mInsets.right));
+        }
+
+        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
+        measureChildWithMargins(mContent, widthMeasureSpec,
+                widthUsed, heightMeasureSpec, heightUsed);
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
+    }
+
     private boolean beginDraggingWidget(WidgetCell v) {
         // Get the widget preview as the drag representation
         WidgetImageView image = v.getWidgetView();
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 91529be..a52adf6 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -180,14 +180,17 @@
     public void applyFromCellItem(WidgetItem item, WidgetPreviewLoader loader) {
         applyPreviewOnAppWidgetHostView(item);
 
+        Context context = getContext();
         mItem = item;
         mWidgetName.setText(mItem.label);
-        mWidgetDims.setText(getContext().getString(R.string.widget_dims_format,
+        mWidgetName.setContentDescription(
+                context.getString(R.string.widget_preview_context_description, mItem.label));
+        mWidgetDims.setText(context.getString(R.string.widget_dims_format,
                 mItem.spanX, mItem.spanY));
-        mWidgetDims.setContentDescription(getContext().getString(
+        mWidgetDims.setContentDescription(context.getString(
                 R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
         if (ATLEAST_S && mItem.widgetInfo != null) {
-            CharSequence description = mItem.widgetInfo.loadDescription(getContext());
+            CharSequence description = mItem.widgetInfo.loadDescription(context);
             if (description != null && description.length() > 0) {
                 mWidgetDescription.setText(description);
                 mWidgetDescription.setVisibility(VISIBLE);
@@ -238,6 +241,7 @@
             NavigableAppWidgetHostView appWidgetHostViewPreview,
             LauncherAppWidgetProviderInfo providerInfo,
             @Nullable RemoteViews remoteViews) {
+        appWidgetHostViewPreview.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         appWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1, providerInfo);
         Rect padding;
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 37b950d..d7928c7 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -23,7 +23,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IntProperty;
-import android.util.Log;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -36,10 +35,7 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
-import androidx.annotation.GuardedBy;
-
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
@@ -53,7 +49,7 @@
 /**
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
-public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
+public class WidgetsBottomSheet extends BaseWidgetSheet {
     private static final String TAG = "WidgetsBottomSheet";
 
     private static final IntProperty<View> PADDING_BOTTOM =
@@ -74,7 +70,6 @@
     private static final long EDUCATION_TIP_DELAY_MS = 300;
 
     private ItemInfo mOriginalItemInfo;
-    private final Rect mInsets;
     private final int mMaxTableHeight;
     private int mMaxHorizontalSpan = 4;
 
@@ -114,7 +109,6 @@
     public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
-        mInsets = new Rect();
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
         // take over the entire view vertically.
@@ -132,53 +126,20 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (doMeasure(widthMeasureSpec, heightMeasureSpec)) {
-            boolean hasUpdated = doMeasure(widthMeasureSpec, heightMeasureSpec);
-            if (hasUpdated) {
-                Log.w(TAG, "WidgetsBottomSheet dimension has been updated after a 2nd"
-                        + " measurement.");
-            }
+        doMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (updateMaxSpansPerRow()) {
+            doMeasure(widthMeasureSpec, heightMeasureSpec);
         }
     }
 
-    /**
-     * Measures the dimension of this view and its children.
-     *
-     * <p>This function takes account of the following during measurement:
-     * <ol>
-     *     <li>status bar and system navigation bar insets</li>
-     *     <li>
-     *         number of spans that can fit in a row. This affects the number of widgets that can
-     *         fit in a row.
-     *     </li>
-     * </ol>
-     *
-     * @return {@code true} if the width or height of this view or its children have changed after
-     *          the measurement. Otherwise, returns {@code false}.
-     */
-    @GuardedBy("MainThread")
-    private boolean doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
-        int widthUsed;
-        if (mInsets.bottom > 0) {
-            widthUsed = mInsets.left + mInsets.right;
-        } else {
-            Rect padding = deviceProfile.workspacePadding;
-            widthUsed = Math.max(padding.left + padding.right,
-                    2 * (mInsets.left + mInsets.right));
-        }
-
-        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, heightUsed);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
+    /** Returns {@code true} if the max spans have been updated. */
+    private boolean updateMaxSpansPerRow() {
+        if (getMeasuredWidth() == 0) return false;
 
         int paddingPx = 2 * getResources().getDimensionPixelOffset(
                 R.dimen.widget_cell_horizontal_padding);
         int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
                 / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
-
         if (mMaxHorizontalSpan != maxHorizontalSpan) {
             // Ensure the table layout is showing widgets in the right column after measure.
             mMaxHorizontalSpan = maxHorizontalSpan;
@@ -297,7 +258,8 @@
 
     @Override
     public void setInsets(Rect insets) {
-        mInsets.set(insets);
+        super.setInsets(insets);
+
         mContent.setPadding(mContent.getPaddingStart(),
                 mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
         if (insets.bottom > 0) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 0106ef5..6c2cca6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -45,8 +45,6 @@
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
@@ -76,7 +74,7 @@
  * Popup for showing the full list of available widgets
  */
 public class WidgetsFullSheet extends BaseWidgetSheet
-        implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
+        implements ProviderChangedListener, OnActivePageChangedListener,
         WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
     private static final String TAG = WidgetsFullSheet.class.getSimpleName();
 
@@ -131,6 +129,22 @@
         }
     };
 
+    private final OnAttachStateChangeListener mBindScrollbarInSearchMode =
+            new OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View view) {
+                    WidgetsRecyclerView searchRecyclerView =
+                            mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView;
+                    if (mIsInSearchMode && searchRecyclerView != null) {
+                        searchRecyclerView.bindFastScrollbar();
+                    }
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View view) {
+                }
+            };
+
     private final int mTabsHeight;
     private final int mViewPagerTopPadding;
     private final int mSearchAndRecommendationContainerBottomMargin;
@@ -305,11 +319,17 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mActivityContext.getAppWidgetHost().removeProviderChangeListener(this);
+        mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView
+                .removeOnAttachStateChangeListener(mBindScrollbarInSearchMode);
+        if (mHasWorkProfile) {
+            mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView
+                    .removeOnAttachStateChangeListener(mBindScrollbarInSearchMode);
+        }
     }
 
     @Override
     public void setInsets(Rect insets) {
-        mInsets.set(insets);
+        super.setInsets(insets);
 
         setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, insets.bottom);
         setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, insets.bottom);
@@ -351,24 +371,6 @@
         }
     }
 
-    private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
-        int widthUsed;
-        if (mInsets.bottom > 0) {
-            widthUsed = mInsets.left + mInsets.right;
-        } else {
-            Rect padding = deviceProfile.workspacePadding;
-            widthUsed = Math.max(padding.left + padding.right,
-                    2 * (mInsets.left + mInsets.right));
-        }
-
-        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, heightUsed);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
-    }
-
     /** Returns {@code true} if the max spans have been updated. */
     private boolean updateMaxSpansPerRow() {
         if (getMeasuredWidth() == 0) return false;
@@ -772,6 +774,12 @@
             mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
             mWidgetsRecyclerView.setEdgeEffectFactory(
                     ((TopRoundedCornerView) mContent).createEdgeEffectFactory());
+            // Recycler view binds to fast scroller when it is attached to screen. Make sure
+            // search recycler view is bound to fast scroller if user is in search mode at the time
+            // of attachment.
+            if (mAdapterType == PRIMARY || mAdapterType == WORK) {
+                mWidgetsRecyclerView.addOnAttachStateChangeListener(mBindScrollbarInSearchMode);
+            }
             mWidgetsListAdapter.setApplyBitmapDeferred(false, mWidgetsRecyclerView);
             mWidgetsListAdapter.setMaxHorizontalSpansPerRow(mMaxSpansPerRow);
         }