Merge "Create new device profile for Android Go." into ub-launcher3-dorval-polish2
diff --git a/go/res/drawable/ic_widget.xml b/go/res/drawable/ic_widget.xml
new file mode 100644
index 0000000..5336876
--- /dev/null
+++ b/go/res/drawable/ic_widget.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M3.9,18.35c2.5-2.49,5.78-3.64,10.14-3.64v3.05c0,0.47,0.57,0.71,0.9,0.37l5.74-5.74c0.41-0.41,0.41-1.08,0-1.49l-5.74-5.74
+        c-0.33-0.33-0.9-0.1-0.9,0.37v2.95c-6.32,0.9-9.56,4.9-11.02,9.34C2.86,18.34,3.51,18.74,3.9,18.35z"/>
+</vector>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index dab0743..ac440fc 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -42,12 +42,7 @@
             android:layout_gravity="center"
             launcher:pageIndicator="@id/page_indicator" />
 
-        <com.android.launcher3.graphics.GradientView
-            android:id="@+id/gradient_bg"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone"
-            launcher:layout_ignoreInsets="true"/>
+        <include layout="@layout/gradient_bg" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index bace51a..c41a6e3 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -44,12 +44,7 @@
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <com.android.launcher3.graphics.GradientView
-            android:id="@+id/gradient_bg"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone"
-            launcher:layout_ignoreInsets="true"/>
+        <include layout="@layout/gradient_bg" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 18d235c..03e42bc 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -43,12 +43,7 @@
             launcher:pageIndicator="@id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <com.android.launcher3.graphics.GradientView
-            android:id="@+id/gradient_bg"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone"
-            launcher:layout_ignoreInsets="true"/>
+        <include layout="@layout/gradient_bg" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
diff --git a/res/layout/gradient_bg.xml b/res/layout/gradient_bg.xml
new file mode 100644
index 0000000..db448d7
--- /dev/null
+++ b/res/layout/gradient_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<com.android.launcher3.graphics.GradientView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/gradient_bg"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone"
+    launcher:layout_ignoreInsets="true" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index cf20feb..1ffe41b 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.content.ComponentName;
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.content.Intent;
@@ -28,13 +29,17 @@
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dynamicui.ExtractionUtils;
+import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.util.ConfigMonitor;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SettingsObserver;
 import com.android.launcher3.util.TestingUtils;
 
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
 public class LauncherAppState {
 
     public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD;
@@ -47,7 +52,7 @@
     private final IconCache mIconCache;
     private final WidgetPreviewLoader mWidgetCache;
     private final InvariantDeviceProfile mInvariantDeviceProfile;
-
+    private final SettingsObserver mNotificationBadgingObserver;
 
     public static LauncherAppState getInstance(final Context context) {
         if (INSTANCE == null) {
@@ -117,6 +122,23 @@
         new ConfigMonitor(mContext).register();
 
         ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
+
+        if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
+            mNotificationBadgingObserver = null;
+        } else {
+            // Register an observer to rebind the notification listener when badging is re-enabled.
+            mNotificationBadgingObserver = new SettingsObserver.Secure(
+                    mContext.getContentResolver()) {
+                @Override
+                public void onSettingChanged(boolean isNotificationBadgingEnabled) {
+                    if (isNotificationBadgingEnabled) {
+                        NotificationListener.requestRebind(new ComponentName(
+                                mContext, NotificationListener.class));
+                    }
+                }
+            };
+            mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+        }
     }
 
     /**
@@ -127,6 +149,9 @@
         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
         launcherApps.removeOnAppsChangedCallback(mModel);
         PackageInstallerCompat.getInstance(mContext).onStop();
+        if (mNotificationBadgingObserver != null) {
+            mNotificationBadgingObserver.unregister();
+        }
     }
 
     LauncherModel setLauncher(Launcher launcher) {
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index fa7769e..9046372 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -26,17 +26,15 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.database.ContentObserver;
 import android.os.Bundle;
-import android.os.Handler;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 import android.provider.Settings;
-import android.provider.Settings.System;
 
 import com.android.launcher3.graphics.IconShapeOverride;
 import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.SettingsObserver;
 import com.android.launcher3.views.ButtonPreference;
 
 /**
@@ -45,8 +43,8 @@
 public class SettingsActivity extends Activity {
 
     private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
-    // TODO: use Settings.Secure.NOTIFICATION_BADGING
-    private static final String NOTIFICATION_BADGING = "notification_badging";
+    /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
+    public static final String NOTIFICATION_BADGING = "notification_badging";
     /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
     private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
 
@@ -88,12 +86,9 @@
 
                 // Register a content observer to listen for system setting changes while
                 // this UI is active.
-                resolver.registerContentObserver(
-                        Settings.System.getUriFor(System.ACCELEROMETER_ROTATION),
-                        false, mRotationLockObserver);
+                mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION);
 
                 // Initialize the UI once
-                mRotationLockObserver.onChange(true);
                 rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
             }
 
@@ -107,13 +102,7 @@
                 // Listen to system notification badge settings while this UI is active.
                 mIconBadgingObserver = new IconBadgingObserver(
                         iconBadgingPref, resolver, getFragmentManager());
-                resolver.registerContentObserver(
-                        Settings.Secure.getUriFor(NOTIFICATION_BADGING),
-                        false, mIconBadgingObserver);
-                resolver.registerContentObserver(
-                        Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
-                        false, mIconBadgingObserver);
-                mIconBadgingObserver.onChange(true);
+                mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS);
             }
 
             Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
@@ -129,11 +118,11 @@
         @Override
         public void onDestroy() {
             if (mRotationLockObserver != null) {
-                getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver);
+                mRotationLockObserver.unregister();
                 mRotationLockObserver = null;
             }
             if (mIconBadgingObserver != null) {
-                getActivity().getContentResolver().unregisterContentObserver(mIconBadgingObserver);
+                mIconBadgingObserver.unregister();
                 mIconBadgingObserver = null;
             }
             super.onDestroy();
@@ -144,22 +133,18 @@
      * Content observer which listens for system auto-rotate setting changes, and enables/disables
      * the launcher rotation setting accordingly.
      */
-    private static class SystemDisplayRotationLockObserver extends ContentObserver {
+    private static class SystemDisplayRotationLockObserver extends SettingsObserver.System {
 
         private final Preference mRotationPref;
-        private final ContentResolver mResolver;
 
         public SystemDisplayRotationLockObserver(
                 Preference rotationPref, ContentResolver resolver) {
-            super(new Handler());
+            super(resolver);
             mRotationPref = rotationPref;
-            mResolver = resolver;
         }
 
         @Override
-        public void onChange(boolean selfChange) {
-            boolean enabled = Settings.System.getInt(mResolver,
-                    Settings.System.ACCELEROMETER_ROTATION, 1) == 1;
+        public void onSettingChanged(boolean enabled) {
             mRotationPref.setEnabled(enabled);
             mRotationPref.setSummary(enabled
                     ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc);
@@ -170,7 +155,7 @@
      * Content observer which listens for system badging setting changes,
      * and updates the launcher badging setting subtext accordingly.
      */
-    private static class IconBadgingObserver extends ContentObserver
+    private static class IconBadgingObserver extends SettingsObserver.Secure
             implements Preference.OnPreferenceClickListener {
 
         private final ButtonPreference mBadgingPref;
@@ -179,15 +164,14 @@
 
         public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
                 FragmentManager fragmentManager) {
-            super(new Handler());
+            super(resolver);
             mBadgingPref = badgingPref;
             mResolver = resolver;
             mFragmentManager = fragmentManager;
         }
 
         @Override
-        public void onChange(boolean selfChange) {
-            boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1;
+        public void onSettingChanged(boolean enabled) {
             int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
 
             boolean serviceEnabled = true;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index d4a7b93..494cd5a 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -111,12 +111,6 @@
     }
 
     @Override
-    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
-        mPullDetector.onTouchEvent(ev);
-        return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll();
-    }
-
-    @Override
     public boolean onTouchEvent(MotionEvent e) {
         mPullDetector.onTouchEvent(e);
         if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) {
@@ -287,7 +281,8 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent e) {
-        boolean result = super.onInterceptTouchEvent(e);
+        mPullDetector.onTouchEvent(e);
+        boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll();
         if (!result && e.getAction() == MotionEvent.ACTION_DOWN
                 && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
             mEmptySearchBackground.setHotspot(e.getX(), e.getY());
@@ -562,11 +557,16 @@
             // and if one of the following criteria are met:
             // - User scrolls down when they're already at the bottom.
             // - User starts scrolling up, hits the top, and continues scrolling up.
+            boolean wasInOverScroll = mIsInOverScroll;
             mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
                     ((!canScrollVertically(1) && displacement < 0) ||
                     (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
 
-            if (mIsInOverScroll) {
+            if (wasInOverScroll && !mIsInOverScroll) {
+                // Exit overscroll. This can happen when the user is in overscroll and then
+                // scrolls the opposite way.
+                reset(false /* shouldSpring */);
+            } else if (mIsInOverScroll) {
                 if (Float.compare(mFirstDisplacement, 0) == 0) {
                     // Because users can scroll before entering overscroll, we need to
                     // subtract the amount where the user was not in overscroll.
@@ -581,11 +581,15 @@
 
         @Override
         public void onDragEnd(float velocity, boolean fling) {
+           reset(mIsInOverScroll  /* shouldSpring */);
+        }
+
+        private void reset(boolean shouldSpring) {
             float y = getContentTranslationY();
             if (Float.compare(y, 0) != 0) {
-                if (FeatureFlags.LAUNCHER3_PHYSICS) {
+                if (FeatureFlags.LAUNCHER3_PHYSICS && shouldSpring) {
                     // We calculate our own velocity to give the springs the desired effect.
-                    velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
+                    float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
                     // We want to negate the velocity because we are moving to 0 from -1 due to the
                     // downward motion. (y-axis -1 is above 0).
                     mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 6896b37..edfe0c1 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -283,7 +283,9 @@
         }
 
         // Use a light system UI (dark icons) if all apps is behind at least half of the status bar.
-        boolean forceChange = shift <= mStatusBarHeight / 2;
+        boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ?
+                shift <= mShiftRange / 4 :
+                shift <= mStatusBarHeight / 2;
         if (forceChange) {
             mLauncher.getSystemUiController().updateUiState(
                     SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 73d89aa..6a70989 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -30,15 +30,20 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SettingsObserver;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
 /**
  * A {@link NotificationListenerService} that sends updates to its
  * {@link NotificationsChangedListener} when notifications are posted or canceled,
@@ -57,12 +62,14 @@
     private static NotificationListener sNotificationListenerInstance = null;
     private static NotificationsChangedListener sNotificationsChangedListener;
     private static boolean sIsConnected;
+    private static boolean sIsCreated;
 
     private final Handler mWorkerHandler;
     private final Handler mUiHandler;
-
     private final Ranking mTempRanking = new Ranking();
 
+    private SettingsObserver mNotificationBadgingObserver;
+
     private final Handler.Callback mWorkerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message message) {
@@ -77,7 +84,7 @@
                     List<StatusBarNotification> activeNotifications;
                     if (sIsConnected) {
                         try {
-                            activeNotifications =  filterNotifications(getActiveNotifications());
+                            activeNotifications = filterNotifications(getActiveNotifications());
                         } catch (SecurityException ex) {
                             Log.e(TAG, "SecurityException: failed to fetch notifications");
                             activeNotifications = new ArrayList<StatusBarNotification>();
@@ -130,6 +137,28 @@
         sNotificationListenerInstance = this;
     }
 
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        sIsCreated = true;
+        mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
+            @Override
+            public void onSettingChanged(boolean isNotificationBadgingEnabled) {
+                if (!isNotificationBadgingEnabled) {
+                    requestUnbind();
+                }
+            }
+        };
+        mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        sIsCreated = false;
+        mNotificationBadgingObserver.unregister();
+    }
+
     public static @Nullable NotificationListener getInstanceIfConnected() {
         return sIsConnected ? sNotificationListenerInstance : null;
     }
@@ -143,6 +172,11 @@
         NotificationListener notificationListener = getInstanceIfConnected();
         if (notificationListener != null) {
             notificationListener.onNotificationFullRefresh();
+        } else if (!sIsCreated && sNotificationsChangedListener != null) {
+            // User turned off badging globally, so we unbound this service;
+            // tell the listener that there are no notifications to remove dots.
+            sNotificationsChangedListener.onNotificationFullRefresh(
+                    Collections.<StatusBarNotification>emptyList());
         }
     }
 
@@ -205,7 +239,7 @@
                 .getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
                         .toArray(new String[keys.size()]));
         return notifications == null
-            ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications);
+                ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications);
     }
 
     /**
diff --git a/src/com/android/launcher3/util/SettingsObserver.java b/src/com/android/launcher3/util/SettingsObserver.java
new file mode 100644
index 0000000..6baa242
--- /dev/null
+++ b/src/com/android/launcher3/util/SettingsObserver.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+public interface SettingsObserver {
+
+    /**
+     * Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the
+     * passed settings change. The value passed to onSettingChanged() is based on the key setting.
+     */
+    void register(String keySetting, String ... dependentSettings);
+    void unregister();
+    void onSettingChanged(boolean keySettingEnabled);
+
+
+    abstract class Secure extends ContentObserver implements SettingsObserver {
+        private ContentResolver mResolver;
+        private String mKeySetting;
+
+        public Secure(ContentResolver resolver) {
+            super(new Handler());
+            mResolver = resolver;
+        }
+
+        @Override
+        public void register(String keySetting, String ... dependentSettings) {
+            mKeySetting = keySetting;
+            mResolver.registerContentObserver(
+                    Settings.Secure.getUriFor(mKeySetting), false, this);
+            for (String setting : dependentSettings) {
+                mResolver.registerContentObserver(
+                        Settings.Secure.getUriFor(setting), false, this);
+            }
+            onChange(true);
+        }
+
+        @Override
+        public void unregister() {
+            mResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1);
+        }
+    }
+
+    abstract class System extends ContentObserver implements SettingsObserver {
+        private ContentResolver mResolver;
+        private String mKeySetting;
+
+        public System(ContentResolver resolver) {
+            super(new Handler());
+            mResolver = resolver;
+        }
+
+        @Override
+        public void register(String keySetting, String ... dependentSettings) {
+            mKeySetting = keySetting;
+            mResolver.registerContentObserver(
+                    Settings.System.getUriFor(mKeySetting), false, this);
+            for (String setting : dependentSettings) {
+                mResolver.registerContentObserver(
+                        Settings.System.getUriFor(setting), false, this);
+            }
+            onChange(true);
+        }
+
+        @Override
+        public void unregister() {
+            mResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 0b4bf62..01101ac 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -88,7 +88,8 @@
         mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
         mInsets = new Rect();
         mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
-        mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
+        mGradientBackground = (GradientView) mLauncher.getLayoutInflater().inflate(
+                R.layout.gradient_bg, mLauncher.getDragLayer(), false);
     }
 
     @Override
@@ -106,6 +107,8 @@
 
         onWidgetsBound();
 
+        mLauncher.getDragLayer().addView(mGradientBackground);
+        mGradientBackground.setVisibility(VISIBLE);
         mLauncher.getDragLayer().addView(this);
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         setTranslationY(mTranslationYClosed);
@@ -212,11 +215,8 @@
             mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    mIsOpen = false;
                     mSwipeDetector.finishedScrolling();
-                    ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
-                    mLauncher.getSystemUiController().updateUiState(
-                            SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+                    onCloseComplete();
                 }
             });
             mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState()
@@ -224,12 +224,18 @@
             mOpenCloseAnimator.start();
         } else {
             setTranslationY(mTranslationYClosed);
-            mLauncher.getSystemUiController().updateUiState(
-                    SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
-            mIsOpen = false;
+            onCloseComplete();
         }
     }
 
+    private void onCloseComplete() {
+        mIsOpen = false;
+        mLauncher.getDragLayer().removeView(mGradientBackground);
+        mLauncher.getDragLayer().removeView(WidgetsBottomSheet.this);
+        mLauncher.getSystemUiController().updateUiState(
+                SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+    }
+
     @Override
     protected boolean isOfType(@FloatingViewType int type) {
         return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;