Merge "Only show App Info drag target if developer settings are enabled." into ub-launcher3-calgary
diff --git a/res/values/config.xml b/res/values/config.xml
index d689f1b..88aa7fd 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -75,6 +75,9 @@
     <!-- Name of an icon provider class. -->
     <string name="icon_provider_class" translatable="false"></string>
 
+    <!-- Package name of the default wallpaper picker. -->
+    <string name="wallpaper_picker_package" translatable="false"></string>
+
     <!-- View ID to use for QSB widget -->
     <item type="id" name="qsb_widget" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 813953e..4c9d0b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -169,7 +169,11 @@
 
     <!-- Strings for settings -->
     <!-- Title for Allow Rotation setting. [CHAR LIMIT=50] -->
-    <string name="allow_rotation_title">Allow rotation</string>
+    <string name="allow_rotation_title">Allow homescreen rotation</string>
+    <!-- Text explaining when the home screen will get rotated. [CHAR LIMIT=100] -->
+    <string name="allow_rotation_desc">When device is rotated</string>
+    <!-- Text explaining that rotation is disabled in Display settings. 'Display' refers to the Display section in system settings [CHAR LIMIT=100] -->
+    <string name="allow_rotation_blocked_desc">Current Display setting doesn\'t permit rotation</string>
 
     <!-- Label on an icon that references an uninstalled package, for which we have no information about when it might be installed. [CHAR_LIMIT=15] -->
     <string name="package_state_unknown">Unknown</string>
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 6c9d969..9a99852 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -109,10 +109,8 @@
         listeners.add(listener);
     }
 
-    void removeListener(FolderListener listener) {
-        if (listeners.contains(listener)) {
-            listeners.remove(listener);
-        }
+    public void removeListener(FolderListener listener) {
+        listeners.remove(listener);
     }
 
     public void itemsChanged(boolean animate) {
@@ -121,12 +119,6 @@
         }
     }
 
-    @Override
-    void unbind() {
-        super.unbind();
-        listeners.clear();
-    }
-
     public interface FolderListener {
         public void onAdd(ShortcutInfo item);
         public void onRemove(ShortcutInfo item);
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 1ba09e1..286a7f1 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -183,15 +183,6 @@
         }
     }
 
-    /**
-     * It is very important that sub-classes implement this if they contain any references
-     * to the activity (anything in the view hierarchy etc.). If not, leaks can result since
-     * ItemInfo objects persist across rotation and can hence leak by holding stale references
-     * to the old view hierarchy / activity.
-     */
-    void unbind() {
-    }
-
     @Override
     public String toString() {
         return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index eacf72a..0a8e1e6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -115,6 +115,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.TestingUtils;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -1567,31 +1568,28 @@
         if (!mRestoring) {
             if (hostView == null) {
                 // Perform actual inflation because we're live
-                launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId,
-                        appWidgetInfo);
-            } else {
-                // The AppWidgetHostView has already been inflated and instantiated
-                launcherInfo.hostView = hostView;
+                hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
             }
-            launcherInfo.hostView.setVisibility(View.VISIBLE);
-            addAppWidgetToWorkspace(launcherInfo, appWidgetInfo, isWorkspaceLocked());
+            hostView.setVisibility(View.VISIBLE);
+            addAppWidgetToWorkspace(hostView, launcherInfo, appWidgetInfo, isWorkspaceLocked());
         }
         resetAddInfo();
     }
 
-    private void addAppWidgetToWorkspace(LauncherAppWidgetInfo item,
+    private void addAppWidgetToWorkspace(
+            AppWidgetHostView hostView, LauncherAppWidgetInfo item,
             LauncherAppWidgetProviderInfo appWidgetInfo, boolean insert) {
-        item.hostView.setTag(item);
-        item.onBindAppWidget(this);
+        hostView.setTag(item);
+        item.onBindAppWidget(this, hostView);
 
-        item.hostView.setFocusable(true);
-        item.hostView.setOnFocusChangeListener(mFocusHandler);
+        hostView.setFocusable(true);
+        hostView.setOnFocusChangeListener(mFocusHandler);
 
-        mWorkspace.addInScreen(item.hostView, item.container, item.screenId,
+        mWorkspace.addInScreen(hostView, item.container, item.screenId,
                 item.cellX, item.cellY, item.spanX, item.spanY, insert);
 
         if (!item.isCustomWidget()) {
-            addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+            addWidgetToAutoAdvanceIfNeeded(hostView, appWidgetInfo);
         }
     }
 
@@ -1969,6 +1967,7 @@
         mHandler.removeMessages(ADVANCE_MSG);
         mHandler.removeMessages(0);
         mWorkspace.removeCallbacks(mBuildLayersRunnable);
+        mWorkspace.removeFolderListeners();
 
         // Stop callbacks from LauncherModel
         // It's possible to receive onDestroy after a new Launcher activity has
@@ -2367,6 +2366,9 @@
             }
         } else if (itemInfo instanceof FolderInfo) {
             final FolderInfo folderInfo = (FolderInfo) itemInfo;
+            if (v instanceof FolderIcon) {
+                ((FolderIcon) v).removeListeners();
+            }
             mWorkspace.removeWorkspaceItem(v);
             if (deleteFromDb) {
                 LauncherModel.deleteFolderAndContentsFromDatabase(this, folderInfo);
@@ -2374,8 +2376,7 @@
         } else if (itemInfo instanceof LauncherAppWidgetInfo) {
             final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
             mWorkspace.removeWorkspaceItem(v);
-            removeWidgetToAutoAdvance(widgetInfo.hostView);
-            widgetInfo.hostView = null;
+            removeWidgetToAutoAdvance(v);
             if (deleteFromDb) {
                 deleteWidgetInfo(widgetInfo);
             }
@@ -2719,10 +2720,17 @@
             return;
         }
 
-        if (LOGD) Log.d(TAG, "onClickWallpaperPicker");
+        String pickerPackage = getString(R.string.wallpaper_picker_package);
+        if (TextUtils.isEmpty(pickerPackage)) {
+            pickerPackage =  PackageManagerHelper.getWallpaperPickerPackage(getPackageManager());
+        }
+
         int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
         float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
-        // TODO: Start the system wallpaper picker
+        startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER)
+                .setPackage(pickerPackage)
+                .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset),
+                REQUEST_PICK_WALLPAPER);
     }
 
     /**
@@ -3860,10 +3868,9 @@
     private void bindSafeModeWidget(LauncherAppWidgetInfo item) {
         PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, true);
         view.updateIcon(mIconCache);
-        item.hostView = view;
-        item.hostView.updateAppWidget(null);
-        item.hostView.setOnClickListener(this);
-        addAppWidgetToWorkspace(item, null, false);
+        view.updateAppWidget(null);
+        view.setOnClickListener(this);
+        addAppWidgetToWorkspace(view, item, null, false);
         mWorkspace.requestLayout();
     }
 
@@ -3976,18 +3983,17 @@
                 return;
             }
 
-            item.hostView = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
             item.minSpanX = appWidgetInfo.minSpanX;
             item.minSpanY = appWidgetInfo.minSpanY;
-            addAppWidgetToWorkspace(item, appWidgetInfo, false);
+            addAppWidgetToWorkspace(
+                    mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo),
+                    item, appWidgetInfo, false);
         } else {
-            PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item,
-                    mIsSafeModeEnabled);
+            PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, false);
             view.updateIcon(mIconCache);
-            item.hostView = view;
-            item.hostView.updateAppWidget(null);
-            item.hostView.setOnClickListener(this);
-            addAppWidgetToWorkspace(item, null, false);
+            view.updateAppWidget(null);
+            view.setOnClickListener(this);
+            addAppWidgetToWorkspace(view, item, null, false);
         }
         mWorkspace.requestLayout();
 
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 55edf45..42d6468 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -80,12 +80,6 @@
 
     private boolean mHasNotifiedInitialWidgetSizeChanged;
 
-    /**
-     * View that holds this widget after it's been created.  This view isn't created
-     * until Launcher knows it's needed.
-     */
-    AppWidgetHostView hostView = null;
-
     LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
         if (appWidgetId == CUSTOM_WIDGET_ID) {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
@@ -121,25 +115,18 @@
      * When we bind the widget, we should notify the widget that the size has changed if we have not
      * done so already (only really for default workspace widgets).
      */
-    void onBindAppWidget(Launcher launcher) {
+    void onBindAppWidget(Launcher launcher, AppWidgetHostView hostView) {
         if (!mHasNotifiedInitialWidgetSizeChanged) {
             AppWidgetResizeFrame.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
             mHasNotifiedInitialWidgetSizeChanged = true;
         }
     }
 
-
     @Override
     public String toString() {
         return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
     }
 
-    @Override
-    void unbind() {
-        super.unbind();
-        hostView = null;
-    }
-
     public final boolean isWidgetIdValid() {
         return (restoreStatus & FLAG_ID_NOT_VALID) == 0;
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index eaeb1ac..3d31b4e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -65,6 +65,7 @@
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.StringFilter;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -578,38 +579,6 @@
         runOnWorkerThread(r);
     }
 
-    private void unbindItemInfosAndClearQueuedBindRunnables() {
-        if (sWorkerThread.getThreadId() == Process.myTid()) {
-            throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
-                    "main thread");
-        }
-
-        // Remove any queued UI runnables
-        mHandler.cancelAll();
-        // Unbind all the workspace items
-        unbindWorkspaceItemsOnMainThread();
-    }
-
-    /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */
-    void unbindWorkspaceItemsOnMainThread() {
-        // Ensure that we don't use the same workspace items data structure on the main thread
-        // by making a copy of workspace items first.
-        final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();
-        synchronized (sBgLock) {
-            tmpItems.addAll(sBgWorkspaceItems);
-            tmpItems.addAll(sBgAppWidgets);
-        }
-        Runnable r = new Runnable() {
-                @Override
-                public void run() {
-                   for (ItemInfo item : tmpItems) {
-                       item.unbind();
-                   }
-                }
-            };
-        runOnMainThread(r);
-    }
-
     /**
      * Adds an item to the DB if it was not created previously, or move it to a new
      * <container, screen, cellX, cellY>
@@ -1137,10 +1106,10 @@
      */
     public void initialize(Callbacks callbacks) {
         synchronized (mLock) {
-            // Disconnect any of the callbacks and drawables associated with ItemInfos on the
-            // workspace to prevent leaking Launcher activities on orientation change.
-            unbindItemInfosAndClearQueuedBindRunnables();
-            mCallbacks = new WeakReference<Callbacks>(callbacks);
+            Preconditions.assertUIThread();
+            // Remove any queued UI runnables
+            mHandler.cancelAll();
+            mCallbacks = new WeakReference<>(callbacks);
         }
     }
 
@@ -2482,10 +2451,6 @@
             final long currentScreenId = currentScreen < 0
                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);
 
-            // Load all the items that are on the current page first (and in the process, unbind
-            // all the existing workspace items before we call startBinding() below.
-            unbindWorkspaceItemsOnMainThread();
-
             // Separate the items that are on the current screen, and all the other remaining items
             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 5cc5aa6..7ebee31 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -323,28 +323,6 @@
         createDbIfNotExists();
 
         switch (method) {
-            case LauncherSettings.Settings.METHOD_GET_BOOLEAN: {
-                Bundle result = new Bundle();
-                if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(arg)) {
-                    result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
-                            Utilities.isAllowRotationPrefEnabled(getContext()));
-                } else {
-                    result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
-                            Utilities.getPrefs(getContext()).getBoolean(arg, extras.getBoolean(
-                                    LauncherSettings.Settings.EXTRA_DEFAULT_VALUE)));
-                }
-                return result;
-            }
-            case LauncherSettings.Settings.METHOD_SET_BOOLEAN: {
-                final boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
-                Utilities.getPrefs(getContext()).edit().putBoolean(arg, value).apply();
-                if (extras.getBoolean(LauncherSettings.Settings.NOTIFY_BACKUP)) {
-                    LauncherBackupAgentHelper.dataChanged(getContext());
-                }
-                Bundle result = new Bundle();
-                result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, value);
-                return result;
-            }
             case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: {
                 String extractedColors = extras.getString(
                         LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 095670d..45a87cc 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -277,8 +277,6 @@
         public static final Uri CONTENT_URI = Uri.parse("content://" +
                 ProviderConfig.AUTHORITY + "/settings");
 
-        public static final String METHOD_GET_BOOLEAN = "get_boolean_setting";
-        public static final String METHOD_SET_BOOLEAN = "set_boolean_setting";
         public static final String METHOD_CLEAR_EMPTY_DB_FLAG = "clear_empty_db_flag";
 
         public static final String METHOD_DELETE_EMPTY_FOLDERS = "delete_empty_folders";
@@ -301,9 +299,6 @@
         public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
 
         public static final String EXTRA_VALUE = "value";
-        public static final String EXTRA_DEFAULT_VALUE = "default_value";
-        // Extra for set_boolean method to also notify the backup manager of the change.
-        public static final String NOTIFY_BACKUP = "notify_backup";
 
         public static Bundle call(ContentResolver cr, String method) {
             return cr.call(CONTENT_URI, method, null, null);
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 4135d5b..5ef6dd5 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -17,13 +17,14 @@
 package com.android.launcher3;
 
 import android.app.Activity;
-import android.os.AsyncTask;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
 import android.os.Bundle;
+import android.os.Handler;
 import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.preference.TwoStatePreference;
+import android.provider.Settings;
+import android.provider.Settings.System;
 
 /**
  * Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -42,56 +43,70 @@
     /**
      * This fragment shows the launcher preferences.
      */
-    public static class LauncherSettingsFragment extends PreferenceFragment
-            implements OnPreferenceChangeListener {
+    public static class LauncherSettingsFragment extends PreferenceFragment {
+
+        private SystemDisplayRotationLockObserver mRotationLockObserver;
+
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
+            getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
             addPreferencesFromResource(R.xml.launcher_preferences);
 
-            PreferenceScreen screen = getPreferenceScreen();
-            for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) {
-                Preference pref = screen.getPreference(i);
-                if (pref instanceof TwoStatePreference) {
-                    setBooleanPrefUsingContentProvider((TwoStatePreference) pref);
-                }
+            // Setup allow rotation preference
+            Preference rotationPref = findPreference(Utilities.ALLOW_ROTATION_PREFERENCE_KEY);
+            if (getResources().getBoolean(R.bool.allow_rotation)) {
+                // Launcher supports rotation by default. No need to show this setting.
+                getPreferenceScreen().removePreference(rotationPref);
+            } else {
+                ContentResolver resolver = getContext().getContentResolver();
+                mRotationLockObserver = new SystemDisplayRotationLockObserver(rotationPref, resolver);
+
+                // 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);
+
+                // Initialize the UI once
+                mRotationLockObserver.onChange(true);
+                rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getContext()));
             }
         }
 
         @Override
-        public boolean onPreferenceChange(Preference preference, Object newValue) {
-            Bundle extras = new Bundle();
-            extras.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, (Boolean) newValue);
-            getActivity().getContentResolver().call(
-                    LauncherSettings.Settings.CONTENT_URI,
-                    LauncherSettings.Settings.METHOD_SET_BOOLEAN,
-                    preference.getKey(), extras);
-            return true;
+        public void onDestroy() {
+            if (mRotationLockObserver != null) {
+                getContext().getContentResolver().unregisterContentObserver(mRotationLockObserver);
+                mRotationLockObserver = null;
+            }
+            super.onDestroy();
+        }
+    }
+
+    /**
+     * 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 final Preference mRotationPref;
+        private final ContentResolver mResolver;
+
+        public SystemDisplayRotationLockObserver(
+                Preference rotationPref, ContentResolver resolver) {
+            super(new Handler());
+            mRotationPref = rotationPref;
+            mResolver = resolver;
         }
 
-        private void setBooleanPrefUsingContentProvider(final TwoStatePreference pref) {
-            pref.setPersistent(false);
-            pref.setEnabled(false);
-
-            new AsyncTask<Void, Void, Boolean>() {
-                @Override
-                protected Boolean doInBackground(Void... params) {
-                    Bundle extras = new Bundle();
-                    extras.putBoolean(LauncherSettings.Settings.EXTRA_DEFAULT_VALUE, true);
-                    Bundle value = pref.getContext().getContentResolver().call(
-                            LauncherSettings.Settings.CONTENT_URI,
-                            LauncherSettings.Settings.METHOD_GET_BOOLEAN,
-                            pref.getKey(), extras);
-                    return value.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
-                }
-
-                @Override
-                protected void onPostExecute(Boolean aBoolean) {
-                    pref.setChecked(aBoolean);
-                    pref.setEnabled(true);
-                    pref.setOnPreferenceChangeListener(LauncherSettingsFragment.this);
-                }
-            }.execute();
+        @Override
+        public void onChange(boolean selfChange) {
+            boolean enabled = Settings.System.getInt(mResolver,
+                    Settings.System.ACCELEROMETER_ROTATION, 1) == 1;
+            mRotationPref.setEnabled(enabled);
+            mRotationPref.setSummary(enabled
+                    ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc);
         }
     }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c5f601d..53522fb 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -142,7 +142,11 @@
     }
 
     public static boolean isAllowRotationPrefEnabled(Context context) {
-        boolean allowRotationPref = false;
+        return getPrefs(context).getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
+                getAllowRotationDefaultValue(context));
+    }
+
+    public static boolean getAllowRotationDefaultValue(Context context) {
         if (isNycOrAbove()) {
             // If the device was scaled, used the original dimensions to determine if rotation
             // is allowed of not.
@@ -153,13 +157,12 @@
                 Resources res = context.getResources();
                 int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
                         * res.getDisplayMetrics().densityDpi / originalDensity;
-                allowRotationPref = originalSmallestWidth >= 600;
+                return originalSmallestWidth >= 600;
             } catch (Exception e) {
                 // Ignore
             }
         }
-
-        return getPrefs(context).getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, allowRotationPref);
+        return false;
     }
 
     public static boolean isNycOrAbove() {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 88e5251..616c356 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1096,10 +1096,11 @@
             for (int j = 0; j < itemCount; j++) {
                 View v = swc.getChildAt(j);
 
-                if (v != null  && v.getTag() instanceof LauncherAppWidgetInfo) {
+                if (v instanceof LauncherAppWidgetHostView
+                        && v.getTag() instanceof LauncherAppWidgetInfo) {
                     LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
-                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
-                    if (lahv != null && lahv.isReinflateRequired()) {
+                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) v;
+                    if (lahv.isReinflateRequired()) {
                         // Remove and rebind the current widget (which was inflated in the wrong
                         // orientation), but don't delete it from the database
                         mLauncher.removeItem(lahv, info, false  /* deleteFromDb */);
@@ -3668,6 +3669,21 @@
         }
     }
 
+    /**
+     * Removes all folder listeners
+     */
+    public void removeFolderListeners() {
+        mapOverItems(false, new ItemOperator() {
+            @Override
+            public boolean evaluate(ItemInfo info, View view) {
+                if (view instanceof FolderIcon) {
+                    ((FolderIcon) view).removeListeners();
+                }
+                return false;
+            }
+        });
+    }
+
     @Override
     public void deferCompleteDropAfterUninstallActivity() {
         mDeferDropAfterUninstall = true;
@@ -4156,7 +4172,7 @@
         });
     }
 
-    public void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) {
+    public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
         if (!changedInfo.isEmpty()) {
             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
                     mLauncher.getAppWidgetHost());
@@ -4177,12 +4193,18 @@
             } else {
                 // widgetRefresh will automatically run when the packages are updated.
                 // For now just update the progress bars
-                for (LauncherAppWidgetInfo info : changedInfo) {
-                    if (info.hostView instanceof PendingAppWidgetHostView) {
-                        info.installProgress = 100;
-                        ((PendingAppWidgetHostView) info.hostView).applyState();
+                mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+                    @Override
+                    public boolean evaluate(ItemInfo info, View view) {
+                        if (view instanceof PendingAppWidgetHostView
+                                && changedInfo.contains(info)) {
+                            ((LauncherAppWidgetInfo) info).installProgress = 100;
+                            ((PendingAppWidgetHostView) view).applyState();
+                        }
+                        // process all the shortcuts
+                        return false;
                     }
-                }
+                });
             }
         }
     }
@@ -4310,14 +4332,18 @@
 
             mRefreshPending = false;
 
-            for (LauncherAppWidgetInfo info : mInfos) {
-                if (info.hostView instanceof PendingAppWidgetHostView) {
-                    // Remove and rebind the current widget, but don't delete it from the database
-                    PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;
-                    mLauncher.removeItem(view, info, false /* deleteFromDb */);
-                    mLauncher.bindAppWidget(info);
+            mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+                @Override
+                public boolean evaluate(ItemInfo info, View view) {
+                    if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
+                        PendingAppWidgetHostView hostView = (PendingAppWidgetHostView) view;
+                        mLauncher.removeItem(view, info, false /* deleteFromDb */);
+                        mLauncher.bindAppWidget((LauncherAppWidgetInfo) info);
+                    }
+                    // process all the shortcuts
+                    return false;
                 }
-            }
+            });
         }
     }
 }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 1e4eb7f..157a970 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -1000,6 +1000,11 @@
         mLongPressHelper.cancelLongPress();
     }
 
+    public void removeListeners() {
+        mInfo.removeListener(this);
+        mInfo.removeListener(mFolder);
+    }
+
     public interface PreviewLayoutRule {
         public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
             PreviewItemDrawingParams params);
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 08e8e86..3c4c79a 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,17 +16,22 @@
 
 package com.android.launcher3.util;
 
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 
 import com.android.launcher3.Utilities;
 
+import java.util.ArrayList;
+
 /**
  * Utility methods using package manager
  */
 public class PackageManagerHelper {
 
     private static final int FLAG_SUSPENDED = 1<<30;
+    private static final String LIVE_WALLPAPER_PICKER_PKG = "com.android.wallpaper.livepicker";
 
     /**
      * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
@@ -68,4 +73,27 @@
             return false;
         }
     }
+
+    /**
+     * Returns the package for a wallpaper picker system app giving preference to a app which
+     * is not as image picker.
+     */
+    public static String getWallpaperPickerPackage(PackageManager pm) {
+        ArrayList<String> excludePackages = new ArrayList<>();
+        // Exclude packages which contain an image picker
+        for (ResolveInfo info : pm.queryIntentActivities(
+                new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), 0)) {
+            excludePackages.add(info.activityInfo.packageName);
+        }
+        excludePackages.add(LIVE_WALLPAPER_PICKER_PKG);
+
+        for (ResolveInfo info : pm.queryIntentActivities(
+                new Intent(Intent.ACTION_SET_WALLPAPER), 0)) {
+            if (!excludePackages.contains(info.activityInfo.packageName) &&
+                    (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                return info.activityInfo.packageName;
+            }
+        }
+        return excludePackages.get(0);
+    }
 }