Modify pin widget dialog open-close animation.

Pin widget sheet should open from bottom up and close on drag down.
Behaviour with navigation bar is similar to that of widgets bottom sheet.

Add a drag layer and reuse AbstractSlideInView for open-close
animation.

Test: Tested manually- opening, closing through dragging/ cancel button/
back button. Adding widget to screen by dragging/ add to home screen
button.
Bug: 186124244

Change-Id: I4b77d5bdd4ed1689b651847dfed69d19cafa7456
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 87a08af..d725a16 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -107,7 +107,7 @@
                        android:value="true" />
 
         <activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
-            android:theme="@style/AppItemActivityTheme"
+            android:theme="@style/AddItemActivityTheme"
             android:excludeFromRecents="true"
             android:autoRemoveFromRecents="true"
             android:exported="true">
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index a2ed211..14b0c5d 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -48,7 +48,7 @@
  * User education dialog for hybrid hotseat. Allows user to migrate hotseat items to a new page in
  * the workspace and shows predictions on the whole hotseat
  */
-public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
+public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements Insettable {
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
     protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
@@ -84,7 +84,7 @@
         mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
         mSampleHotseat = findViewById(R.id.sample_prediction);
 
-        DeviceProfile grid = mLauncher.getDeviceProfile();
+        DeviceProfile grid = mActivityContext.getDeviceProfile();
         Rect padding = grid.getHotseatLayoutPadding();
 
         mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
@@ -110,13 +110,13 @@
 
         mHotseatEduController.moveHotseatItems();
         mHotseatEduController.finishOnboarding();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ACCEPT);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ACCEPT);
     }
 
     private void onDismiss(View v) {
         mHotseatEduController.showDimissTip();
         mHotseatEduController.finishOnboarding();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_DENY);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_DENY);
         handleClose(true);
     }
 
@@ -131,12 +131,12 @@
         int rightInset = insets.right - mInsets.right;
         int bottomInset = insets.bottom - mInsets.bottom;
         mInsets.set(insets);
-        if (mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
+        if (mActivityContext.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
             setPadding(leftInset, getPaddingTop(), rightInset, 0);
             mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
                     mHotseatWrapper.getPaddingRight(), bottomInset);
             mHotseatWrapper.getLayoutParams().height =
-                    mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom;
+                    mActivityContext.getDeviceProfile().hotseatBarSizePx + insets.bottom;
 
         } else {
             setPadding(0, getPaddingTop(), 0, 0);
@@ -178,7 +178,7 @@
     }
 
     private void populatePreview(List<WorkspaceItemInfo> predictions) {
-        for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
+        for (int i = 0; i < mActivityContext.getDeviceProfile().numShownHotseatIcons; i++) {
             WorkspaceItemInfo info = predictions.get(i);
             PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
             icon.setEnabled(false);
@@ -194,13 +194,13 @@
      */
     public void show(List<WorkspaceItemInfo> predictions) {
         if (getParent() != null
-                || predictions.size() < mLauncher.getDeviceProfile().numShownHotseatIcons
+                || predictions.size() < mActivityContext.getDeviceProfile().numShownHotseatIcons
                 || mHotseatEduController == null) {
             return;
         }
-        AbstractFloatingView.closeAllOpenViews(mLauncher);
+        AbstractFloatingView.closeAllOpenViews(mActivityContext);
         attachToContainer();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
         animateOpen();
         populatePreview(predictions);
     }
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 00d148f..0a3fbbc 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -16,69 +16,85 @@
 ** limitations under the License.
 */
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/add_item_confirmation"
+<com.android.launcher3.dragndrop.AddItemDragLayer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/add_item_drag_layer"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:padding="24dp"
-    android:theme="?attr/widgetsTheme"
-    android:orientation="vertical">
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:importantForAccessibility="no">
 
-    <TextView
-        style="@style/TextHeadline"
-        android:id="@+id/widget_appName"
+    <com.android.launcher3.widget.AddItemWidgetsBottomSheet
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/add_item_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textSize="24sp"
-        android:ellipsize="end"
-        android:fadingEdge="horizontal"
-        android:singleLine="true"
-        android:maxLines="1" />
+        android:background="@drawable/add_item_dialog_background"
+        android:padding="24dp"
+        android:theme="?attr/widgetsTheme"
+        android:layout_gravity="bottom"
+        android:orientation="vertical">
 
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:paddingVertical="8dp"
-        android:text="@string/add_item_request_drag_hint"
-        android:textSize="14sp"
-        android:textColor="?android:attr/textColorSecondary"
-        android:alpha="0.7"
-        android:importantForAccessibility="no"/>
-
-    <include layout="@layout/widget_cell"
-        android:id="@+id/widget_cell"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:layout_marginVertical="16dp" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="end"
-        android:padding="8dp"
-        android:orientation="horizontal">
-        <Button
-            style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
-            android:layout_width="wrap_content"
+        <TextView
+            style="@style/TextHeadline"
+            android:id="@+id/widget_appName"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingHorizontal="16dp"
-            android:onClick="onCancelClick"
-            android:text="@android:string/cancel" />
+            android:gravity="center_horizontal"
+            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="24sp"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:singleLine="true"
+            android:maxLines="1" />
 
-        <Space
-            android:layout_width="4dp"
-            android:layout_height="wrap_content" />
-
-        <Button
-            style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
-            android:layout_width="wrap_content"
+        <TextView
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingHorizontal="16dp"
-            android:onClick="onPlaceAutomaticallyClick"
-            android:text="@string/add_to_home_screen" />
-    </LinearLayout>
-</LinearLayout>
+            android:gravity="center_horizontal"
+            android:paddingVertical="8dp"
+            android:text="@string/add_item_request_drag_hint"
+            android:textSize="14sp"
+            android:textColor="?android:attr/textColorSecondary"
+            android:alpha="0.7"
+            android:importantForAccessibility="no"/>
+
+        <include layout="@layout/widget_cell"
+            android:id="@+id/widget_cell"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_marginVertical="16dp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:padding="8dp"
+            android:orientation="horizontal">
+            <Button
+                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="16dp"
+                android:onClick="onCancelClick"
+                android:text="@android:string/cancel" />
+
+            <Space
+                android:layout_width="4dp"
+                android:layout_height="wrap_content" />
+
+            <Button
+                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="16dp"
+                android:onClick="onPlaceAutomaticallyClick"
+                android:text="@string/add_to_home_screen"/>
+        </LinearLayout>
+    </com.android.launcher3.widget.AddItemWidgetsBottomSheet>
+
+</com.android.launcher3.dragndrop.AddItemDragLayer>
+
+
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 07a5096..427525b 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 /*
-* Copyright (C) 2018 The Android Open Source Project
+* Copyright (C) 2008 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.
@@ -18,11 +18,7 @@
 -->
 
 <resources>
-
-    <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+    <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
-        <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
-        <item name="android:windowNoTitle">true</item>
     </style>
-
-</resources>
\ No newline at end of file
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index fa41b1a..9bc3af5 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -149,12 +149,6 @@
     <style name="AppTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark.DarkMainColor" />
     <style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
 
-    <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
-        <item name="widgetsTheme">@style/WidgetContainerTheme</item>
-        <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
-        <item name="android:windowNoTitle">true</item>
-    </style>
-
     <style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:navigationBarColor">?android:colorPrimaryDark</item>
         <item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
@@ -291,4 +285,8 @@
     <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">
         <item name="android:background">@drawable/add_item_dialog_button_background</item>
     </style>
+
+    <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+        <item name="widgetsTheme">@style/WidgetContainerTheme</item>
+    </style>
 </resources>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 32b2c9a..b3952ca 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -63,7 +63,8 @@
             TYPE_DRAG_DROP_POPUP,
             TYPE_TASK_MENU,
             TYPE_OPTIONS_POPUP,
-            TYPE_ICON_SURFACE
+            TYPE_ICON_SURFACE,
+            TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FloatingViewType {}
@@ -84,11 +85,13 @@
     public static final int TYPE_OPTIONS_POPUP = 1 << 12;
     public static final int TYPE_ICON_SURFACE = 1 << 13;
 
+    public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 14;
+
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
             | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
             | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
-            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP;
+            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 5ba36f2..5dae5a6 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -30,6 +30,7 @@
 import android.content.ClipDescription;
 import android.content.Intent;
 import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -37,7 +38,6 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -56,6 +56,8 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PinRequestHelper;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.views.AbstractSlideInView;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -69,8 +71,12 @@
 
 import java.util.function.Supplier;
 
+/**
+ * Activity to show pin widget dialog.
+ */
 @TargetApi(Build.VERSION_CODES.O)
-public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
+public class AddItemActivity extends BaseActivity
+        implements OnLongClickListener, OnTouchListener, AbstractSlideInView.OnCloseListener {
 
     private static final int SHADOW_SIZE = 10;
 
@@ -82,6 +88,7 @@
     private PinItemRequest mRequest;
     private LauncherAppState mApp;
     private InvariantDeviceProfile mIdp;
+    private BaseDragLayer<AddItemActivity> mDragLayer;
 
     private WidgetCell mWidgetCell;
 
@@ -111,6 +118,14 @@
         mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
 
         setContentView(R.layout.add_item_confirmation_activity);
+        // Set flag to allow activity to draw over navigation and status bar.
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        mDragLayer = findViewById(R.id.add_item_drag_layer);
+        mDragLayer.recreateControllers();
+        mDragLayer.setInsets(mDeviceProfile.getInsets());
+        AbstractSlideInView<AddItemActivity> slideInView = findViewById(R.id.add_item_bottom_sheet);
+        slideInView.addOnCloseListener(this);
         mWidgetCell = findViewById(R.id.widget_cell);
 
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -135,6 +150,8 @@
 
         TextView widgetAppName = findViewById(R.id.widget_appName);
         widgetAppName.setText(getApplicationInfo().labelRes);
+
+        setupNavBarColor();
     }
 
     @Override
@@ -338,7 +355,20 @@
 
     @Override
     public BaseDragLayer getDragLayer() {
-        throw new UnsupportedOperationException();
+        return mDragLayer;
+    }
+
+    @Override
+    public void onSlideInViewClosed() {
+        finish();
+    }
+
+    protected void setupNavBarColor() {
+        boolean isSheetDark = (getApplicationContext().getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+        getSystemUiController().updateUiState(
+                SystemUiController.UI_STATE_BASE_WINDOW,
+                isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
     }
 
     private void logCommand(StatsLogManager.EventEnum command) {
@@ -346,15 +376,4 @@
                 .withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
                 .log(command);
     }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        View view = getWindow().getDecorView();
-        WindowManager.LayoutParams layoutParams =
-                (WindowManager.LayoutParams) view.getLayoutParams();
-        layoutParams.gravity = Gravity.BOTTOM;
-        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
-        getWindowManager().updateViewLayout(view, layoutParams);
-    }
 }
diff --git a/src/com/android/launcher3/dragndrop/AddItemDragLayer.java b/src/com/android/launcher3/dragndrop/AddItemDragLayer.java
new file mode 100644
index 0000000..5b52c3d
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/AddItemDragLayer.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.dragndrop;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * Drag layer for {@link AddItemActivity}.
+ */
+public class AddItemDragLayer extends BaseDragLayer<AddItemActivity> {
+
+    public AddItemDragLayer(Context context, AttributeSet attrs) {
+        this(context, attrs, /*alphaChannelCount= */ 1);
+    }
+
+    public AddItemDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
+        super(context, attrs, alphaChannelCount);
+    }
+
+    @Override
+    public void recreateControllers() {
+        mControllers = new TouchController[] {};
+    }
+}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index f79313f..92ca8a1 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -31,17 +31,21 @@
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.touch.BaseSwipeDetector;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
- * Extension of AbstractFloatingView with common methods for sliding in from bottom
+ * Extension of {@link AbstractFloatingView} with common methods for sliding in from bottom.
+ *
+ * @param <T> Type of ActivityContext inflating this view.
  */
-public abstract class AbstractSlideInView extends AbstractFloatingView
-        implements SingleAxisSwipeDetector.Listener {
+public abstract class AbstractSlideInView<T extends Context & ActivityContext>
+        extends AbstractFloatingView implements SingleAxisSwipeDetector.Listener {
 
     protected static final Property<AbstractSlideInView, Float> TRANSLATION_SHIFT =
             new Property<AbstractSlideInView, Float>(Float.class, "translationShift") {
@@ -59,7 +63,8 @@
     protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
     protected static final float TRANSLATION_SHIFT_OPENED = 0f;
 
-    protected final Launcher mLauncher;
+    protected final T mActivityContext;
+
     protected final SingleAxisSwipeDetector mSwipeDetector;
     protected final ObjectAnimator mOpenCloseAnimator;
 
@@ -71,10 +76,11 @@
     protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED;
 
     protected boolean mNoIntercept;
+    protected List<OnCloseListener> mOnCloseListeners = new ArrayList<>();
 
     public AbstractSlideInView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mLauncher = Launcher.getLauncher(context);
+        mActivityContext = ActivityContext.lookupContext(context);
 
         mScrollInterpolator = Interpolators.SCROLL_CUBIC;
         mSwipeDetector = new SingleAxisSwipeDetector(context, this,
@@ -88,8 +94,8 @@
                 announceAccessibilityChanges();
             }
         });
-        int scrimColor = getScrimColor(mLauncher);
-        mColorScrim = scrimColor != -1 ? createColorScrim(mLauncher, scrimColor) : null;
+        int scrimColor = getScrimColor(context);
+        mColorScrim = scrimColor != -1 ? createColorScrim(context, scrimColor) : null;
     }
 
     protected void attachToContainer() {
@@ -120,8 +126,8 @@
             return false;
         }
 
-        int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
-                SingleAxisSwipeDetector.DIRECTION_NEGATIVE : 0;
+        int directionsToDetectScroll = mSwipeDetector.isIdleState()
+                ? SingleAxisSwipeDetector.DIRECTION_NEGATIVE : 0;
         mSwipeDetector.setDetectableScrollConditions(
                 directionsToDetectScroll, false);
         mSwipeDetector.onTouchEvent(ev);
@@ -176,6 +182,11 @@
         }
     }
 
+    /** Registers an {@link OnCloseListener}. */
+    public void addOnCloseListener(OnCloseListener listener) {
+        mOnCloseListeners.add(listener);
+    }
+
     protected void handleClose(boolean animate, long defaultDuration) {
         if (!mIsOpen) {
             return;
@@ -210,10 +221,11 @@
         if (mColorScrim != null) {
             getPopupContainer().removeView(mColorScrim);
         }
+        mOnCloseListeners.forEach(OnCloseListener::onSlideInViewClosed);
     }
 
     protected BaseDragLayer getPopupContainer() {
-        return mLauncher.getDragLayer();
+        return mActivityContext.getDragLayer();
     }
 
     protected View createColorScrim(Context context, int bgColor) {
@@ -227,4 +239,15 @@
 
         return view;
     }
+
+    /**
+     * Interface to report that the {@link AbstractSlideInView} has closed.
+     */
+    public interface OnCloseListener {
+
+        /**
+         * Called when {@link AbstractSlideInView} closes.
+         */
+        void onSlideInViewClosed();
+    }
 }
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index c8cf627..6be0c23 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -42,7 +42,7 @@
 /**
  * On boarding flow for users right after setting up work profile
  */
-public class WorkEduView extends AbstractSlideInView
+public class WorkEduView extends AbstractSlideInView<Launcher>
         implements Insettable, StateListener<LauncherState> {
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
@@ -76,14 +76,15 @@
 
     @Override
     protected void handleClose(boolean animate) {
-        mLauncher.getSharedPrefs().edit().putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
+        mActivityContext.getSharedPrefs().edit()
+                .putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
         handleClose(true, DEFAULT_CLOSE_DURATION);
     }
 
     @Override
     protected void onCloseComplete() {
         super.onCloseComplete();
-        mLauncher.getStateManager().removeStateListener(this);
+        mActivityContext.getStateManager().removeStateListener(this);
     }
 
     @Override
@@ -116,13 +117,14 @@
             animator.addListener(new AnimationSuccessListener() {
                 @Override
                 public void onAnimationSuccess(Animator animator) {
-                    mContentText.setText(mLauncher.getString(R.string.work_profile_edu_work_apps));
+                    mContentText.setText(
+                            mActivityContext.getString(R.string.work_profile_edu_work_apps));
                     ObjectAnimator.ofFloat(mContentText, ALPHA, 1).start();
                 }
             });
             animator.start();
         } else {
-            mContentText.setText(mLauncher.getString(R.string.work_profile_edu_work_apps));
+            mContentText.setText(mActivityContext.getString(R.string.work_profile_edu_work_apps));
         }
         mNextWorkEduStep = WORK_EDU_WORK_APPS;
         mProceedButton.setOnClickListener(v -> handleClose(true));
@@ -142,7 +144,7 @@
     private void show() {
         attachToContainer();
         animateOpen();
-        mLauncher.getStateManager().addStateListener(this);
+        mActivityContext.getStateManager().addStateListener(this);
     }
 
     @Override
@@ -168,7 +170,7 @@
     }
 
     private AllAppsPagedView getAllAppsPagedView() {
-        View v = mLauncher.getAppsView().getContentView();
+        View v = mActivityContext.getAppsView().getContentView();
         return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
     }
 
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
new file mode 100644
index 0000000..9e08303
--- /dev/null
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.widget;
+
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.dragndrop.AddItemActivity;
+import com.android.launcher3.views.AbstractSlideInView;
+
+/**
+ * Bottom sheet for the pin widget.
+ */
+public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivity>
+        implements Insettable {
+
+    private static final int DEFAULT_CLOSE_DURATION = 200;
+
+    private Rect mInsets;
+    private Configuration mCurrentConfiguration;
+
+    public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContent = this;
+        mInsets = new Rect();
+        mCurrentConfiguration = new Configuration(getResources().getConfiguration());
+        animateOpen();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        setTranslationShift(mTranslationShift);
+    }
+
+    private void animateOpen() {
+        if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+            return;
+        }
+        mIsOpen = true;
+        mOpenCloseAnimator.setValues(
+                PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+        mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        mOpenCloseAnimator.start();
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        handleClose(animate, DEFAULT_CLOSE_DURATION);
+    }
+
+    @Override
+    protected boolean isOfType(@FloatingViewType int type) {
+        return (type & TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP) != 0;
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        // Extend behind left, right, and bottom insets.
+        int leftInset = insets.left - mInsets.left;
+        int rightInset = insets.right - mInsets.right;
+        int bottomInset = insets.bottom - mInsets.bottom;
+        mInsets.set(insets);
+        setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mCurrentConfiguration.orientation != newConfig.orientation) {
+            mInsets.setEmpty();
+        }
+        mCurrentConfiguration.updateFrom(newConfig);
+    }
+}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index a7ecb07..f7e295e 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -28,6 +28,7 @@
 
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
@@ -42,11 +43,10 @@
 /**
  * Base class for various widgets popup
  */
-public abstract class BaseWidgetSheet extends AbstractSlideInView
+public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
         implements OnClickListener, OnLongClickListener, DragSource,
         PopupDataProvider.PopupDataChangeListener {
 
-
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
 
@@ -62,13 +62,13 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mLauncher.getPopupDataProvider().setChangeListener(this);
+        mActivityContext.getPopupDataProvider().setChangeListener(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mLauncher.getPopupDataProvider().setChangeListener(null);
+        mActivityContext.getPopupDataProvider().setChangeListener(null);
     }
 
     @Override
@@ -91,7 +91,7 @@
     public boolean onLongClick(View v) {
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
         v.cancelLongPress();
-        if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
+        if (!ItemLongClickListener.canStartDrag(mActivityContext)) return false;
 
         if (v instanceof WidgetCell) {
             return beginDraggingWidget((WidgetCell) v);
@@ -160,7 +160,7 @@
     }
 
     protected SystemUiController getSystemUiController() {
-        return mLauncher.getSystemUiController();
+        return mActivityContext.getSystemUiController();
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 995ac47..787a2d1 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -83,7 +83,7 @@
         setWillNotDraw(false);
         mInsets = new Rect();
         mContent = this;
-        DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+        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.
         mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3  * deviceProfile.cellHeightPx;
@@ -97,7 +97,7 @@
         int paddingPx = 2 * getResources().getDimensionPixelOffset(
                 R.dimen.widget_cell_horizontal_padding);
         int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
-                / (mLauncher.getDeviceProfile().cellWidthPx + paddingPx);
+                / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
 
         if (mMaxHorizontalSpan != maxHorizontalSpan) {
             // Ensure the table layout is showing widgets in the right column after measure.
@@ -134,7 +134,7 @@
 
     @Override
     public void onWidgetsBound() {
-        List<WidgetItem> widgets = mLauncher.getPopupDataProvider().getWidgetsForPackageUser(
+        List<WidgetItem> widgets = mActivityContext.getPopupDataProvider().getWidgetsForPackageUser(
                 new PackageUserKey(
                         mOriginalItemInfo.getTargetComponent().getPackageName(),
                         mOriginalItemInfo.user));
@@ -148,7 +148,7 @@
             row.forEach(widgetItem -> {
                 WidgetCell widget = addItemCell(tableRow);
                 widget.setPreviewSize(widgetItem.spanX, widgetItem.spanY);
-                widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mLauncher)
+                widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mActivityContext)
                         .getWidgetCache());
                 widget.ensurePreview();
                 widget.setVisibility(View.VISIBLE);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 4d8c1ca..0ea50e6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -207,7 +207,7 @@
         onWidgetsBound();
 
         mSearchAndRecommendationViewHolder.mSearchBar.initialize(
-                mLauncher.getPopupDataProvider(), /* searchModeListener= */ this);
+                mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
 
         if (!hasSeenEducationTip()) {
             addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
@@ -271,7 +271,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mLauncher.getAppWidgetHost().addProviderChangeListener(this);
+        mActivityContext.getAppWidgetHost().addProviderChangeListener(this);
         notifyWidgetProvidersChanged();
         onRecommendedWidgetsBound();
     }
@@ -279,7 +279,7 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mLauncher.getAppWidgetHost().removeProviderChangeListener(this);
+        mActivityContext.getAppWidgetHost().removeProviderChangeListener(this);
     }
 
     @Override
@@ -327,7 +327,7 @@
     }
 
     private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (mInsets.bottom > 0) {
             widthUsed = mInsets.left + mInsets.right;
@@ -350,7 +350,7 @@
 
         int previousMaxSpansPerRow = mMaxSpansPerRow;
         mMaxSpansPerRow = getMeasuredWidth()
-                / (mLauncher.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
+                / (mActivityContext.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
 
         if (previousMaxSpansPerRow != mMaxSpansPerRow) {
             mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
@@ -383,7 +383,7 @@
 
     @Override
     public void notifyWidgetProvidersChanged() {
-        mLauncher.refreshAndBindWidgetsForPackageUser(null);
+        mActivityContext.refreshAndBindWidgetsForPackageUser(null);
     }
 
     @Override
@@ -391,7 +391,8 @@
         if (mIsInSearchMode) {
             return;
         }
-        List<WidgetsListBaseEntry> allWidgets = mLauncher.getPopupDataProvider().getAllWidgets();
+        List<WidgetsListBaseEntry> allWidgets =
+                mActivityContext.getPopupDataProvider().getAllWidgets();
 
         AdapterHolder primaryUserAdapterHolder = mAdapters.get(AdapterHolder.PRIMARY);
         primaryUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
@@ -468,12 +469,12 @@
             return;
         }
         List<WidgetItem> recommendedWidgets =
-                mLauncher.getPopupDataProvider().getRecommendedWidgets();
+                mActivityContext.getPopupDataProvider().getRecommendedWidgets();
         WidgetsRecommendationTableLayout table =
                 mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable;
         if (recommendedWidgets.size() > 0) {
             float maxTableHeight =
-                    (mLauncher.getDeviceProfile().availableHeightPx - mTabsHeight
+                    (mActivityContext.getDeviceProfile().availableHeightPx - mTabsHeight
                             - getHeaderViewHeight()) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
             List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
                     WidgetsTableUtils.groupWidgetItemsIntoTable(recommendedWidgets,
@@ -614,10 +615,11 @@
     }
 
     private void showEducationTipOnView(View view) {
-        mLauncher.getSharedPrefs().edit().putBoolean(WIDGETS_EDUCATION_TIP_SEEN, true).apply();
+        mActivityContext.getSharedPrefs().edit()
+                .putBoolean(WIDGETS_EDUCATION_TIP_SEEN, true).apply();
         int[] coords = new int[2];
         view.getLocationOnScreen(coords);
-        ArrowTipView arrowTipView = new ArrowTipView(mLauncher);
+        ArrowTipView arrowTipView = new ArrowTipView(mActivityContext);
         arrowTipView.showAtLocation(
                 getContext().getString(R.string.long_press_widget_to_add),
                 /* arrowXCoord= */coords[0] + view.getWidth() / 2,
@@ -653,7 +655,7 @@
     }
 
     private boolean hasSeenEducationTip() {
-        return mLauncher.getSharedPrefs().getBoolean(WIDGETS_EDUCATION_TIP_SEEN, false)
+        return mActivityContext.getSharedPrefs().getBoolean(WIDGETS_EDUCATION_TIP_SEEN, false)
                 || Utilities.IS_RUNNING_IN_TEST_HARNESS;
     }