Merge "Show error toast messages when there is no room for the item when icon is not to be added to folder." into ub-launcher3-master
diff --git a/res/drawable-hdpi/quantum_panel_bitmap.9.png b/res/drawable-hdpi/quantum_panel_bitmap.9.png
deleted file mode 100644
index d2aee73..0000000
--- a/res/drawable-hdpi/quantum_panel_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png
deleted file mode 100644
index 78345b8..0000000
--- a/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel_bitmap.9.png b/res/drawable-mdpi/quantum_panel_bitmap.9.png
deleted file mode 100644
index 9325d49..0000000
--- a/res/drawable-mdpi/quantum_panel_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png
deleted file mode 100644
index bf74fa0..0000000
--- a/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-v21/quantum_panel.xml b/res/drawable-v21/quantum_panel.xml
deleted file mode 100644
index d1c0783..0000000
--- a/res/drawable-v21/quantum_panel.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/quantum_panel_shape"
-    android:insetBottom="@dimen/quantum_panel_outer_padding"
-    android:insetLeft="@dimen/quantum_panel_outer_padding"
-    android:insetRight="@dimen/quantum_panel_outer_padding"
-    android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/drawable-v21/quantum_panel_dark.xml b/res/drawable-v21/quantum_panel_dark.xml
deleted file mode 100644
index 405ad51..0000000
--- a/res/drawable-v21/quantum_panel_dark.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/quantum_panel_shape_dark"
-    android:insetBottom="@dimen/quantum_panel_outer_padding"
-    android:insetLeft="@dimen/quantum_panel_outer_padding"
-    android:insetRight="@dimen/quantum_panel_outer_padding"
-    android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/drawable-xhdpi/quantum_panel_bitmap.9.png b/res/drawable-xhdpi/quantum_panel_bitmap.9.png
deleted file mode 100644
index b89e8b4..0000000
--- a/res/drawable-xhdpi/quantum_panel_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png
deleted file mode 100644
index 1d17136..0000000
--- a/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel_bitmap.9.png b/res/drawable-xxhdpi/quantum_panel_bitmap.9.png
deleted file mode 100644
index 1dd1f6d..0000000
--- a/res/drawable-xxhdpi/quantum_panel_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png
deleted file mode 100644
index 48d584b..0000000
--- a/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png b/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png
deleted file mode 100644
index 915177d..0000000
--- a/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png
deleted file mode 100644
index 27b8466..0000000
--- a/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/quantum_panel.xml b/res/drawable/quantum_panel.xml
index 1f4fb71..fda1003 100644
--- a/res/drawable/quantum_panel.xml
+++ b/res/drawable/quantum_panel.xml
@@ -14,5 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/quantum_panel_bitmap" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:drawable="@drawable/quantum_panel_shape"
+       android:insetBottom="@dimen/quantum_panel_outer_padding"
+       android:insetLeft="@dimen/quantum_panel_outer_padding"
+       android:insetRight="@dimen/quantum_panel_outer_padding"
+       android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/drawable/quantum_panel_dark.xml b/res/drawable/quantum_panel_dark.xml
index 6642e78..b113b37 100644
--- a/res/drawable/quantum_panel_dark.xml
+++ b/res/drawable/quantum_panel_dark.xml
@@ -14,5 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/quantum_panel_dark_bitmap" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:drawable="@drawable/quantum_panel_shape_dark"
+       android:insetBottom="@dimen/quantum_panel_outer_padding"
+       android:insetLeft="@dimen/quantum_panel_outer_padding"
+       android:insetRight="@dimen/quantum_panel_outer_padding"
+       android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/layout/qsb_blocker_view.xml b/res/layout/qsb_blocker_view.xml
index 58a148e..453eebe 100644
--- a/res/layout/qsb_blocker_view.xml
+++ b/res/layout/qsb_blocker_view.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.QsbBlockerView
+<com.android.launcher3.qsb.QsbBlockerView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/res/layout/qsb_container.xml b/res/layout/qsb_container.xml
index b75e3b5..6fa843d 100644
--- a/res/layout/qsb_container.xml
+++ b/res/layout/qsb_container.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.QsbContainerView
+<com.android.launcher3.qsb.QsbContainerView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:orientation="vertical"
         android:layout_width="match_parent"
@@ -23,8 +23,8 @@
         android:padding="0dp" >
 
     <fragment
-        android:name="com.android.launcher3.QsbContainerView$QsbFragment"
+        android:name="com.android.launcher3.qsb.QsbContainerView$QsbFragment"
         android:layout_width="match_parent"
         android:tag="qsb_view"
         android:layout_height="match_parent"/>
-</com.android.launcher3.QsbContainerView>
\ No newline at end of file
+</com.android.launcher3.qsb.QsbContainerView>
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 4e39ed3..6fdf454 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -48,7 +47,6 @@
     private int mDownX;
     private int mDownY;
     private int mLastY;
-    protected Rect mBackgroundPadding = new Rect();
 
     public BaseRecyclerView(Context context) {
         this(context, null);
@@ -164,21 +162,11 @@
         return false;
     }
 
-    public void updateBackgroundPadding(Rect padding) {
-        mBackgroundPadding.set(padding);
-    }
-
-    public Rect getBackgroundPadding() {
-        return mBackgroundPadding;
-    }
-
     /**
-     * Returns the visible height of the recycler view:
-     *   VisibleHeight = View height - top padding - bottom padding
+     * Returns the height of the fast scroll bar
      */
-    protected int getVisibleHeight() {
-        int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom;
-        return visibleHeight;
+    protected int getScrollbarTrackHeight() {
+        return getHeight();
     }
 
     /**
@@ -192,7 +180,7 @@
      *   AvailableScrollBarHeight = Total height of the visible view - thumb height
      */
     protected int getAvailableScrollBarHeight() {
-        int availableScrollBarHeight = getVisibleHeight() - mScrollbar.getThumbHeight();
+        int availableScrollBarHeight = getScrollbarTrackHeight() - mScrollbar.getThumbHeight();
         return availableScrollBarHeight;
     }
 
@@ -204,13 +192,6 @@
     }
 
     /**
-     * Returns the inactive thumb color, can be overridden by each subclass.
-     */
-    public int getFastScrollerThumbInactiveColor(int defaultInactiveThumbColor) {
-        return defaultInactiveThumbColor;
-    }
-
-    /**
      * Returns the scrollbar for this recycler view.
      */
     public BaseRecyclerViewFastScrollBar getScrollBar() {
@@ -234,7 +215,6 @@
     protected void synchronizeScrollBarThumbOffsetToViewScroll(int scrollY,
             int availableScrollHeight) {
         // Only show the scrollbar if there is height to be scrolled
-        int availableScrollBarHeight = getAvailableScrollBarHeight();
         if (availableScrollHeight <= 0) {
             mScrollbar.setThumbOffsetY(-1);
             return;
@@ -243,8 +223,8 @@
         // Calculate the current scroll position, the scrollY of the recycler view accounts for the
         // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
         // padding)
-        int scrollBarY = mBackgroundPadding.top +
-                (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
+        int scrollBarY =
+                (int) (((float) scrollY / availableScrollHeight) * getAvailableScrollBarHeight());
 
         // Calculate the position and size of the scroll bar
         mScrollbar.setThumbOffsetY(scrollBarY);
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
index 263e132..40c5ed6 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -150,7 +150,7 @@
         }
         int left = getDrawLeft();
         // Invalidate the whole scroll bar area.
-        mRv.invalidate(left, 0, left + mMaxWidth, mRv.getVisibleHeight());
+        mRv.invalidate(left, 0, left + mMaxWidth, mRv.getScrollbarTrackHeight());
 
         mWidth = width;
         updateThumbPath();
@@ -218,11 +218,9 @@
                 }
                 if (mIsDragging) {
                     // Update the fastscroller section name at this touch position
-                    int top = mRv.getBackgroundPadding().top;
-                    int bottom = top + mRv.getVisibleHeight() - mThumbHeight;
-                    float boundedY = (float) Math.max(top, Math.min(bottom, y - mTouchOffsetY));
-                    String sectionName = mRv.scrollToPositionAtProgress((boundedY - top) /
-                            (bottom - top));
+                    int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
+                    float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
+                    String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
                     if (!sectionName.equals(mPopupSectionName)) {
                         mPopupSectionName = sectionName;
                         mPopupView.setText(sectionName);
@@ -257,7 +255,7 @@
         }
         // Draw the track
         int thumbWidth = mIsRtl ? mWidth : -mWidth;
-        canvas.drawRect(0, 0, thumbWidth, mRv.getVisibleHeight(), mTrackPaint);
+        canvas.drawRect(0, 0, thumbWidth, mRv.getScrollbarTrackHeight(), mTrackPaint);
 
         canvas.translate(0, mThumbOffsetY);
         canvas.drawPath(mThumbPath, mThumbPaint);
@@ -299,7 +297,7 @@
     private void updatePopupY(int lastTouchY) {
         int height = mPopupView.getHeight();
         float top = lastTouchY - (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * height);
-        top = Math.max(mMaxWidth, Math.min(top, mRv.getVisibleHeight() - mMaxWidth - height));
+        top = Math.max(mMaxWidth, Math.min(top, mRv.getScrollbarTrackHeight() - mMaxWidth - height));
         mPopupView.setTranslationY(top);
     }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index e830250..655c218 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -463,7 +463,6 @@
     public void layout(Launcher launcher, boolean notifyListeners) {
         FrameLayout.LayoutParams lp;
         boolean hasVerticalBarLayout = isVerticalBarLayout();
-        final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
 
         // Layout the search bar space
         Point searchBarBounds = getSearchBarDimensForWidgetOpts();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c894ea4..3149ce4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -69,7 +69,6 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -173,9 +172,6 @@
     static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
             "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
 
-    public static final String ACTION_APPWIDGET_HOST_RESET =
-            "com.android.launcher3.intent.ACTION_APPWIDGET_HOST_RESET";
-
     // Type: int
     private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
     // Type: int
@@ -206,18 +202,6 @@
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
     @Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
 
-    private final BroadcastReceiver mUiBroadcastReceiver = new BroadcastReceiver() {
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (ACTION_APPWIDGET_HOST_RESET.equals(intent.getAction())) {
-                if (mAppWidgetHost != null) {
-                    mAppWidgetHost.startListening();
-                }
-            }
-        }
-    };
-
     @Thunk Workspace mWorkspace;
     private View mLauncherView;
     @Thunk DragLayer mDragLayer;
@@ -441,9 +425,6 @@
         mDefaultKeySsb = new SpannableStringBuilder();
         Selection.setSelection(mDefaultKeySsb, 0);
 
-        IntentFilter filter = new IntentFilter(ACTION_APPWIDGET_HOST_RESET);
-        registerReceiver(mUiBroadcastReceiver, filter);
-
         mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
         // In case we are on a device with locked rotation, we should look at preferences to check
         // if the user has specifically allowed rotation.
@@ -467,6 +448,13 @@
         loadExtractedColorsAndColorItems();
     }
 
+    @Override
+    public void onAppWidgetHostReset() {
+        if (mAppWidgetHost != null) {
+            mAppWidgetHost.startListening();
+        }
+    }
+
     private void loadExtractedColorsAndColorItems() {
         // TODO: do this in pre-N as well, once the extraction part is complete.
         if (Utilities.isNycOrAbove()) {
@@ -570,7 +558,7 @@
     }
 
     @Override
-    public void onLauncherProviderChange() {
+    public void onLauncherProviderChanged() {
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onLauncherProviderChange();
         }
@@ -1660,13 +1648,6 @@
         return mDeviceProfile;
     }
 
-    public void closeSystemDialogs() {
-        getWindow().closeAllPanels();
-
-        // Whatever we were doing is hereby canceled.
-        setWaitingForResult(null);
-    }
-
     @Override
     protected void onNewIntent(Intent intent) {
         long startTime = 0;
@@ -1685,9 +1666,6 @@
 
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
         if (isActionMain) {
-            // also will cancel mWaitingForResult.
-            closeSystemDialogs();
-
             if (mWorkspace == null) {
                 // Can be cases where mWorkspace is null, this prevents a NPE
                 return;
@@ -1825,8 +1803,6 @@
         ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
                 .removeAccessibilityStateChangeListener(this);
 
-        unregisterReceiver(mUiBroadcastReceiver);
-
         LauncherAnimUtils.onDestroyActivity();
 
         if (mLauncherCallbacks != null) {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index fa5e519..b3db092 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -63,8 +63,6 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mChildrenFocused;
 
-    protected int mErrorViewId = R.layout.appwidget_error;
-
     private boolean mIsAttachedToWindow;
     private boolean mIsAutoAdvanceRegistered;
     private Runnable mAutoAdvanceRunnable;
@@ -81,7 +79,7 @@
 
     @Override
     protected View getErrorView() {
-        return mInflater.inflate(mErrorViewId, this, false);
+        return mInflater.inflate(R.layout.appwidget_error, this, false);
     }
 
     public void updateLastInflationOrientation() {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 229dd9c..349f094 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -649,11 +649,8 @@
             // Database was just created, so wipe any previous widgets
             if (mWidgetHostResetHandler != null) {
                 new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
-                mWidgetHostResetHandler.sendMessage(Message.obtain(
-                        mWidgetHostResetHandler,
-                        ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET,
-                        mContext
-                ));
+                mWidgetHostResetHandler.sendEmptyMessage(
+                        ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED);
             }
 
             // Set the flag for empty DB
@@ -1136,17 +1133,13 @@
             if (mListener != null) {
                 switch (msg.what) {
                     case MSG_LAUNCHER_PROVIDER_CHANGED:
-                        mListener.onLauncherProviderChange();
+                        mListener.onLauncherProviderChanged();
                         break;
                     case MSG_EXTRACTED_COLORS_CHANGED:
                         mListener.onExtractedColorsChanged();
                         break;
                     case MSG_APP_WIDGET_HOST_RESET:
-                        Context context = (Context) msg.obj;
-                        if (context != null) {
-                            context.sendBroadcast(new Intent(Launcher.ACTION_APPWIDGET_HOST_RESET)
-                                    .setPackage(context.getPackageName()));
-                        }
+                        mListener.onAppWidgetHostReset();
                         break;
                 }
             }
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 5998dad..7044812 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -7,7 +7,9 @@
  */
 public interface LauncherProviderChangeListener {
 
-    public void onLauncherProviderChange();
+    void onLauncherProviderChanged();
 
-    public void onExtractedColorsChanged();
+    void onExtractedColorsChanged();
+
+    void onAppWidgetHostReset();
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a32a9b1..ab34287 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -162,27 +162,10 @@
         }
     }
 
-    /**
-     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
-     * background bounds.
-     */
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        // Clip to ensure that we don't draw the overscroll effect beyond the background bounds
-        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
-                getWidth() - mBackgroundPadding.right,
-                getHeight() - mBackgroundPadding.bottom);
-        super.dispatchDraw(canvas);
-    }
-
     @Override
     public void onDraw(Canvas c) {
         // Draw the background
         if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
-            c.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
-                    getWidth() - mBackgroundPadding.right,
-                    getHeight() - mBackgroundPadding.bottom);
-
             mEmptySearchBackground.draw(c);
         }
 
@@ -319,8 +302,8 @@
                 // Calculate the current scroll position, the scrollY of the recycler view accounts
                 // for the view padding, while the scrollBarY is drawn right up to the background
                 // padding (ignoring padding)
-                int scrollBarY = mBackgroundPadding.top +
-                        (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
+                int scrollBarY = (int)
+                        (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
 
                 int thumbScrollY = mScrollbar.getThumbOffsetY();
                 int diffScrollY = scrollBarY - thumbScrollY;
@@ -411,8 +394,8 @@
     }
 
     @Override
-    protected int getVisibleHeight() {
-        return super.getVisibleHeight()
+    protected int getScrollbarTrackHeight() {
+        return super.getScrollbarTrackHeight()
                 - Launcher.getLauncher(getContext()).getDragLayer().getInsets().bottom;
     }
 
@@ -424,7 +407,7 @@
     protected int getAvailableScrollHeight() {
         int paddedHeight = getCurrentScrollY(mApps.getAdapterItems().size(), 0);
         int totalHeight = paddedHeight + getPaddingBottom();
-        return totalHeight - getVisibleHeight();
+        return totalHeight - getScrollbarTrackHeight();
     }
 
     /**
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 019a174..59d18c2 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -145,10 +145,12 @@
         setChildrenDrawingOrderEnabled(true);
 
         final Resources res = getResources();
-        mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
-        mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
-        mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
-        mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
+        if (FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
+            mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
+            mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
+            mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
+            mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
+        }
         mIsRtl = Utilities.isRtl(res);
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
     }
diff --git a/src/com/android/launcher3/QsbBlockerView.java b/src/com/android/launcher3/qsb/QsbBlockerView.java
similarity index 91%
rename from src/com/android/launcher3/QsbBlockerView.java
rename to src/com/android/launcher3/qsb/QsbBlockerView.java
index 6a2bce0..5379336 100644
--- a/src/com/android/launcher3/QsbBlockerView.java
+++ b/src/com/android/launcher3/qsb/QsbBlockerView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.qsb;
 
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -27,12 +27,15 @@
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.Workspace.OnStateChangeListener;
 import com.android.launcher3.Workspace.State;
 
 /**
  * A simple view used to show the region blocked by QSB during drag and drop.
  */
-public class QsbBlockerView extends View implements Workspace.OnStateChangeListener {
+public class QsbBlockerView extends View implements OnStateChangeListener {
 
     private static final int VISIBLE_ALPHA = 100;
 
diff --git a/src/com/android/launcher3/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
similarity index 60%
rename from src/com/android/launcher3/QsbContainerView.java
rename to src/com/android/launcher3/qsb/QsbContainerView.java
index ef478e2..c83143b 100644
--- a/src/com/android/launcher3/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.qsb;
 
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.SearchManager;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.AttributeSet;
@@ -35,6 +34,11 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 
 /**
@@ -68,25 +72,14 @@
         private static final int REQUEST_BIND_QSB = 1;
         private static final String QSB_WIDGET_ID = "qsb_widget_id";
 
-        private static int sSavedWidgetId = -1;
-
+        private QsbWidgetHost mQsbWidgetHost;
         private AppWidgetProviderInfo mWidgetInfo;
-        private LauncherAppWidgetHostView mQsb;
-
-        private BroadcastReceiver mRebindReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                rebindFragment();
-            }
-        };
+        private QsbWidgetHostView mQsb;
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-
-            IntentFilter filter = new IntentFilter(Launcher.ACTION_APPWIDGET_HOST_RESET);
-            filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
-            getActivity().registerReceiver(mRebindReceiver, filter);
+            mQsbWidgetHost = new QsbWidgetHost(getActivity());
         }
 
         private FrameLayout mWrapper;
@@ -95,110 +88,96 @@
         public View onCreateView(
                 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 
-            if (savedInstanceState != null) {
-                sSavedWidgetId = savedInstanceState.getInt(QSB_WIDGET_ID, -1);
-            }
             mWrapper = new FrameLayout(getActivity());
-            mWrapper.addView(createQsb(inflater, mWrapper));
+            mWrapper.addView(createQsb(mWrapper));
             return mWrapper;
         }
 
-        private View createQsb(LayoutInflater inflater, ViewGroup container) {
-            Launcher launcher = Launcher.getLauncher(getActivity());
-            mWidgetInfo = getSearchWidgetProvider(launcher);
+        private View createQsb(ViewGroup container) {
+            Activity activity = getActivity();
+            mWidgetInfo = getSearchWidgetProvider(activity);
             if (mWidgetInfo == null) {
                 // There is no search provider, just show the default widget.
-                return getDefaultView(inflater, container, false);
-            } else {
-                mWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(launcher, mWidgetInfo);
+                return QsbWidgetHostView.getDefaultView(container);
             }
 
-            SharedPreferences prefs = Utilities.getPrefs(launcher);
-            AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(launcher);
-            LauncherAppWidgetHost widgetHost = launcher.getAppWidgetHost();
+            AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(activity);
             InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
 
             Bundle opts = new Bundle();
-            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(launcher, idp.numColumns, 1, null);
+            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(activity, idp.numColumns, 1, null);
             opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
             opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
             opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
             opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
 
-            int widgetId = prefs.getInt(QSB_WIDGET_ID, -1);
+            int widgetId = Utilities.getPrefs(activity).getInt(QSB_WIDGET_ID, -1);
             AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
             boolean isWidgetBound = (widgetInfo != null) &&
                     widgetInfo.provider.equals(mWidgetInfo.provider);
 
+            int oldWidgetId = widgetId;
             if (!isWidgetBound) {
-                // widgetId is already bound and its not the correct provider.
-                // Delete the widget id.
                 if (widgetId > -1) {
-                    widgetHost.deleteAppWidgetId(widgetId);
+                    // widgetId is already bound and its not the correct provider. reset host.
+                    mQsbWidgetHost.deleteHost();
+                }
+
+                widgetId = mQsbWidgetHost.allocateAppWidgetId();
+                isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
+                if (!isWidgetBound) {
+                    mQsbWidgetHost.deleteAppWidgetId(widgetId);
                     widgetId = -1;
                 }
 
-                widgetId = widgetHost.allocateAppWidgetId();
-                isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
-                if (!isWidgetBound) {
-                    widgetHost.deleteAppWidgetId(widgetId);
-                    widgetId = -1;
+                if (oldWidgetId != widgetId) {
+                    saveWidgetId(widgetId);
                 }
             }
 
             if (isWidgetBound) {
-                mQsb = (LauncherAppWidgetHostView)
-                        widgetHost.createView(launcher, widgetId, mWidgetInfo);
+                mQsb = (QsbWidgetHostView) mQsbWidgetHost.createView(activity, widgetId, mWidgetInfo);
                 mQsb.setId(R.id.qsb_widget);
-                mQsb.mErrorViewId = R.layout.qsb_default_view;
 
-                if (!Utilities.containsAll(AppWidgetManager.getInstance(launcher)
+                if (!Utilities.containsAll(AppWidgetManager.getInstance(activity)
                         .getAppWidgetOptions(widgetId), opts)) {
                     mQsb.updateAppWidgetOptions(opts);
                 }
                 mQsb.setPadding(0, 0, 0, 0);
+                mQsbWidgetHost.startListening();
                 return mQsb;
             }
 
             // Return a default widget with setup icon.
-            return getDefaultView(inflater, container, true);
+            View v = QsbWidgetHostView.getDefaultView(container);
+            View setupButton = v.findViewById(R.id.btn_qsb_setup);
+            setupButton.setVisibility(View.VISIBLE);
+            setupButton.setOnClickListener(this);
+            return v;
+        }
+
+        private void saveWidgetId(int widgetId) {
+            Utilities.getPrefs(getActivity()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
         }
 
         @Override
         public void onClick(View view) {
-            if (view.getId() == R.id.btn_qsb_search) {
-                getActivity().startSearch("", false, null, true);
-            } else if (view.getId() == R.id.btn_qsb_setup) {
-                // Allocate a new widget id for QSB
-                sSavedWidgetId = Launcher.getLauncher(getActivity())
-                        .getAppWidgetHost().allocateAppWidgetId();
-                // Start intent for bind the widget
-                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, sSavedWidgetId);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
-                startActivityForResult(intent, REQUEST_BIND_QSB);
-            }
-        }
-
-        @Override
-        public void onSaveInstanceState(Bundle outState) {
-            super.onSaveInstanceState(outState);
-            outState.putInt(QSB_WIDGET_ID, sSavedWidgetId);
+            // Start intent for bind the widget
+            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
+            // Allocate a new widget id for QSB
+            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mQsbWidgetHost.allocateAppWidgetId());
+            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
+            startActivityForResult(intent, REQUEST_BIND_QSB);
         }
 
         @Override
         public void onActivityResult(int requestCode, int resultCode, Intent data) {
             if (requestCode == REQUEST_BIND_QSB) {
                 if (resultCode == Activity.RESULT_OK) {
-                    int widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
-                            sSavedWidgetId);
-                    Utilities.getPrefs(getActivity()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
-                    sSavedWidgetId = -1;
+                    saveWidgetId(data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1));
                     rebindFragment();
-                } else if (sSavedWidgetId != -1) {
-                    Launcher.getLauncher(getActivity()).getAppWidgetHost()
-                            .deleteAppWidgetId(sSavedWidgetId);
-                    sSavedWidgetId = -1;
+                } else {
+                    mQsbWidgetHost.deleteHost();
                 }
             }
         }
@@ -213,27 +192,16 @@
 
         @Override
         public void onDestroy() {
-            getActivity().unregisterReceiver(mRebindReceiver);
+            mQsbWidgetHost.stopListening();
             super.onDestroy();
         }
 
         private void rebindFragment() {
             if (mWrapper != null && getActivity() != null) {
                 mWrapper.removeAllViews();
-                mWrapper.addView(createQsb(getActivity().getLayoutInflater(), mWrapper));
+                mWrapper.addView(createQsb(mWrapper));
             }
         }
-
-        private View getDefaultView(LayoutInflater inflater, ViewGroup parent, boolean showSetup) {
-            View v = inflater.inflate(R.layout.qsb_default_view, parent, false);
-            if (showSetup) {
-                View setupButton = v.findViewById(R.id.btn_qsb_setup);
-                setupButton.setVisibility(View.VISIBLE);
-                setupButton.setOnClickListener(this);
-            }
-            v.findViewById(R.id.btn_qsb_search).setOnClickListener(this);
-            return v;
-        }
     }
 
     /**
@@ -263,4 +231,19 @@
         }
         return defaultWidgetForSearchPackage;
     }
+
+    private static class QsbWidgetHost extends AppWidgetHost {
+
+        private static final int QSB_WIDGET_HOST_ID = 1026;
+
+        public QsbWidgetHost(Context context) {
+            super(context, QSB_WIDGET_HOST_ID);
+        }
+
+        @Override
+        protected AppWidgetHostView onCreateView(
+                Context context, int appWidgetId, AppWidgetProviderInfo appWidget) {
+            return new QsbWidgetHostView(context);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
new file mode 100644
index 0000000..8b6fa16
--- /dev/null
+++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.qsb;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.widget.RemoteViews;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+/**
+ * Appwidget host view with QSB specific logic.
+ */
+public class QsbWidgetHostView extends AppWidgetHostView {
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private int mPreviousOrientation;
+
+    public QsbWidgetHostView(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void updateAppWidget(RemoteViews remoteViews) {
+        // Store the orientation in which the widget was inflated
+        mPreviousOrientation = getResources().getConfiguration().orientation;
+        super.updateAppWidget(remoteViews);
+    }
+
+
+    public boolean isReinflateRequired() {
+        // Re-inflate is required if the orientation has changed since last inflation.
+        return mPreviousOrientation != getResources().getConfiguration().orientation;
+    }
+
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        try {
+            super.onLayout(changed, left, top, right, bottom);
+        } catch (final RuntimeException e) {
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    // Update the widget with 0 Layout id, to reset the view to error view.
+                    updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
+                }
+            });
+        }
+    }
+
+    @Override
+    protected View getErrorView() {
+        return getDefaultView(this);
+    }
+
+    public static View getDefaultView(ViewGroup parent) {
+        View v = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.qsb_default_view, parent, false);
+        v.findViewById(R.id.btn_qsb_search).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Launcher.getLauncher(view.getContext()).startSearch("", false, null, true);
+            }
+        });
+        return v;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index c33978e..4b23ae0 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.widget;
 
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.support.v7.widget.LinearLayoutManager;
 import android.util.AttributeSet;
@@ -71,18 +70,6 @@
     public void setWidgets(WidgetsModel widgets) {
         mWidgets = widgets;
     }
-    
-    /**
-     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
-     * background bounds.
-     */
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
-                getWidth() - mBackgroundPadding.right,
-                getHeight() - mBackgroundPadding.bottom);
-        super.dispatchDraw(canvas);
-    }
 
     /**
      * Maps the touch (from 0..1) to the adapter position that should be visible.
@@ -152,7 +139,7 @@
         View child = getChildAt(0);
         int height = child.getMeasuredHeight() * mWidgets.getPackageSize();
         int totalHeight = getPaddingTop() + height + getPaddingBottom();
-        int availableScrollHeight = totalHeight - getVisibleHeight();
+        int availableScrollHeight = totalHeight - getScrollbarTrackHeight();
         return availableScrollHeight;
     }