Merge "Temporarily tweaking the all apps layout to fit the screen on tablets." into ub-launcher3-burnaby
diff --git a/WallpaperPicker/src/com/android/photos/views/Pools.java b/WallpaperPicker/src/com/android/photos/views/Pools.java
deleted file mode 100644
index c60f2f0..0000000
--- a/WallpaperPicker/src/com/android/photos/views/Pools.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2009 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.photos.views;
-
-/**
- * Helper class for crating pools of objects. An example use looks like this:
- * <pre>
- * public class MyPooledClass {
- *
- *     private static final SynchronizedPool<MyPooledClass> sPool =
- *             new SynchronizedPool<MyPooledClass>(10);
- *
- *     public static MyPooledClass obtain() {
- *         MyPooledClass instance = sPool.acquire();
- *         return (instance != null) ? instance : new MyPooledClass();
- *     }
- *
- *     public void recycle() {
- *          // Clear state if needed.
- *          sPool.release(this);
- *     }
- *
- *     . . .
- * }
- * </pre>
- *
- * @hide
- */
-public final class Pools {
-
-    /**
-     * Interface for managing a pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static interface Pool<T> {
-
-        /**
-         * @return An instance from the pool if such, null otherwise.
-         */
-        public T acquire();
-
-        /**
-         * Release an instance to the pool.
-         *
-         * @param instance The instance to release.
-         * @return Whether the instance was put in the pool.
-         *
-         * @throws IllegalStateException If the instance is already in the pool.
-         */
-        public boolean release(T instance);
-    }
-
-    private Pools() {
-        /* do nothing - hiding constructor */
-    }
-
-    /**
-     * Simple (non-synchronized) pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static class SimplePool<T> implements Pool<T> {
-        private final Object[] mPool;
-
-        private int mPoolSize;
-
-        /**
-         * Creates a new instance.
-         *
-         * @param maxPoolSize The max pool size.
-         *
-         * @throws IllegalArgumentException If the max pool size is less than zero.
-         */
-        public SimplePool(int maxPoolSize) {
-            if (maxPoolSize <= 0) {
-                throw new IllegalArgumentException("The max pool size must be > 0");
-            }
-            mPool = new Object[maxPoolSize];
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public T acquire() {
-            if (mPoolSize > 0) {
-                final int lastPooledIndex = mPoolSize - 1;
-                T instance = (T) mPool[lastPooledIndex];
-                mPool[lastPooledIndex] = null;
-                mPoolSize--;
-                return instance;
-            }
-            return null;
-        }
-
-        @Override
-        public boolean release(T instance) {
-            if (isInPool(instance)) {
-                throw new IllegalStateException("Already in the pool!");
-            }
-            if (mPoolSize < mPool.length) {
-                mPool[mPoolSize] = instance;
-                mPoolSize++;
-                return true;
-            }
-            return false;
-        }
-
-        private boolean isInPool(T instance) {
-            for (int i = 0; i < mPoolSize; i++) {
-                if (mPool[i] == instance) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Synchronized) pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static class SynchronizedPool<T> extends SimplePool<T> {
-        private final Object mLock = new Object();
-
-        /**
-         * Creates a new instance.
-         *
-         * @param maxPoolSize The max pool size.
-         *
-         * @throws IllegalArgumentException If the max pool size is less than zero.
-         */
-        public SynchronizedPool(int maxPoolSize) {
-            super(maxPoolSize);
-        }
-
-        @Override
-        public T acquire() {
-            synchronized (mLock) {
-                return super.acquire();
-            }
-        }
-
-        @Override
-        public boolean release(T element) {
-            synchronized (mLock) {
-                return super.release(element);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
index 39a73b9..e57ce70 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
@@ -20,6 +20,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.support.v4.util.Pools.Pool;
+import android.support.v4.util.Pools.SynchronizedPool;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -31,8 +33,6 @@
 import com.android.gallery3d.glrenderer.GLCanvas;
 import com.android.gallery3d.glrenderer.UploadedTexture;
 import com.android.launcher3.util.Thunk;
-import com.android.photos.views.Pools.Pool;
-import com.android.photos.views.Pools.SynchronizedPool;
 
 /**
  * Handles laying out, decoding, and drawing of tiles in GL
diff --git a/res/anim/fade_in_fast.xml b/res/anim/fade_in_fast.xml
deleted file mode 100644
index 4fa9847..0000000
--- a/res/anim/fade_in_fast.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
-
-    android:fromAlpha="0.0"
-    android:toAlpha="1.0"
-
-    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/res/anim/fade_out_fast.xml b/res/anim/fade_out_fast.xml
deleted file mode 100644
index a061a6c..0000000
--- a/res/anim/fade_out_fast.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
-
-    android:fromAlpha="1.0"
-    android:toAlpha="0.0"
-
-    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/res/anim/no_anim.xml b/res/anim/no_anim.xml
deleted file mode 100644
index 02b1625..0000000
--- a/res/anim/no_anim.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="417" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7f79b98..1b58d75 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -174,11 +174,6 @@
     <string name="permdesc_install_shortcut">Allows an app to add
         shortcuts without user intervention.</string>
     <!-- Permission short label -->
-    <string name="permlab_uninstall_shortcut">uninstall shortcuts</string>
-    <!-- Permission description -->
-    <string name="permdesc_uninstall_shortcut">Allows the app to remove
-        shortcuts without user intervention.</string>
-    <!-- Permission short label -->
     <string name="permlab_read_settings">read Home settings and shortcuts</string>
     <!-- Permission description -->
     <string name="permdesc_read_settings">Allows the app to read the settings and
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index c1d2738..8d1db63 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -4,14 +4,76 @@
 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
 
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 
 
 /**
+ * A private class to manage access to an app name comparator.
+ */
+class AppNameComparator {
+    private UserManagerCompat mUserManager;
+    private Comparator<AppInfo> mAppNameComparator;
+    private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
+
+    public AppNameComparator(Context context) {
+        final Collator collator = Collator.getInstance();
+        mUserManager = UserManagerCompat.getInstance(context);
+        mAppNameComparator = new Comparator<AppInfo>() {
+            public final int compare(AppInfo a, AppInfo b) {
+                // Order by the title
+                int result = collator.compare(a.title.toString().trim(),
+                        b.title.toString().trim());
+                if (result == 0) {
+                    // If two apps have the same title, then order by the component name
+                    result = a.componentName.compareTo(b.componentName);
+                    if (result == 0) {
+                        // If the two apps are the same component, then prioritize by the order that
+                        // the app user was created (prioritizing the main user's apps)
+                        if (UserHandleCompat.myUserHandle().equals(a.user)) {
+                            return -1;
+                        } else {
+                            Long aUserSerial = getAndCacheUserSerial(a.user);
+                            Long bUserSerial = getAndCacheUserSerial(b.user);
+                            return aUserSerial.compareTo(bUserSerial);
+                        }
+                    }
+                }
+                return result;
+            }
+        };
+    }
+
+    /**
+     * Returns a locale-aware comparator that will alphabetically order a list of applications.
+     */
+    public Comparator<AppInfo> getComparator() {
+        // Clear the user serial cache so that we get serials as needed in the comparator
+        mUserSerialCache.clear();
+        return mAppNameComparator;
+    }
+
+    /**
+     * Returns the user serial for this user, using a cached serial if possible.
+     */
+    private Long getAndCacheUserSerial(UserHandleCompat user) {
+        Long userSerial = mUserSerialCache.get(user);
+        if (userSerial == null) {
+            userSerial = mUserManager.getSerialNumberForUser(user);
+            mUserSerialCache.put(user, userSerial);
+        }
+        return userSerial;
+    }
+}
+
+/**
  * The alphabetically sorted list of applications.
  */
 public class AlphabeticalAppsList {
@@ -19,31 +81,74 @@
     /**
      * Info about a section in the alphabetic list
      */
-    public class SectionInfo {
+    public static class SectionInfo {
+        // The name of this section
         public String sectionName;
+        // The number of applications in this section
         public int numAppsInSection;
+        // The first app AdapterItem for this section
+        public AdapterItem firstAppItem;
+
+        public SectionInfo(String name) {
+            sectionName = name;
+        }
+    }
+
+    /**
+     * Info about a particular adapter item (can be either section or app)
+     */
+    public static class AdapterItem {
+        // The index of this adapter item in the list
+        public int position;
+        // Whether or not the item at this adapter position is a section or not
+        public boolean isSectionHeader;
+        // The name of this section, or the section that this app is contained in
+        public String sectionName;
+        // The associated AppInfo, or null if this adapter item is a section
+        public AppInfo appInfo;
+        // The index of this app (not including sections), or -1 if this adapter item is a section
+        public int appIndex;
+
+        public static AdapterItem asSection(int pos, String name) {
+            AdapterItem item = new AdapterItem();
+            item.position = pos;
+            item.isSectionHeader = true;
+            item.sectionName = name;
+            item.appInfo = null;
+            item.appIndex = -1;
+            return item;
+        }
+
+        public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo, int appIndex) {
+            AdapterItem item = new AdapterItem();
+            item.position = pos;
+            item.isSectionHeader = false;
+            item.sectionName = sectionName;
+            item.appInfo = appInfo;
+            item.appIndex = appIndex;
+            return item;
+        }
     }
 
     /**
      * A filter interface to limit the set of applications in the apps list.
      */
     public interface Filter {
-        public boolean retainApp(AppInfo info);
+        public boolean retainApp(AppInfo info, String sectionName);
     }
 
-    // Hack to force RecyclerView to break sections
-    public static final AppInfo SECTION_BREAK_INFO = null;
-
     private List<AppInfo> mApps = new ArrayList<>();
     private List<AppInfo> mFilteredApps = new ArrayList<>();
-    private List<AppInfo> mSectionedFilteredApps = new ArrayList<>();
+    private List<AdapterItem> mSectionedFilteredApps = new ArrayList<>();
     private List<SectionInfo> mSections = new ArrayList<>();
     private RecyclerView.Adapter mAdapter;
     private Filter mFilter;
     private AlphabeticIndexCompat mIndexer;
+    private AppNameComparator mAppNameComparator;
 
     public AlphabeticalAppsList(Context context) {
         mIndexer = new AlphabeticIndexCompat(context);
+        mAppNameComparator = new AppNameComparator(context);
     }
 
     /**
@@ -63,29 +168,15 @@
     /**
      * Returns the current filtered list of applications broken down into their sections.
      */
-    public List<AppInfo> getApps() {
+    public List<AdapterItem> getAdapterItems() {
         return mSectionedFilteredApps;
     }
 
     /**
-     * Returns the current filtered list of applications.
+     * Returns the number of applications in this list.
      */
-    public List<AppInfo> getAppsWithoutSectionBreaks() {
-        return mFilteredApps;
-    }
-
-    /**
-     * Returns the section name for the application.
-     */
-    public String getSectionNameForApp(AppInfo info) {
-        return mIndexer.computeSectionName(info.title.toString().trim());
-    }
-
-    /**
-     * Returns the indexer for this locale.
-     */
-    public AlphabeticIndexCompat getIndexer() {
-        return mIndexer;
+    public int getSize() {
+        return mFilteredApps.size();
     }
 
     /**
@@ -108,7 +199,7 @@
      * Sets the current set of apps.
      */
     public void setApps(List<AppInfo> apps) {
-        Collections.sort(apps, LauncherModel.getAppNameComparator());
+        Collections.sort(apps, mAppNameComparator.getComparator());
         mApps.clear();
         mApps.addAll(apps);
         onAppsUpdated();
@@ -183,8 +274,7 @@
      * Implementation to actually add an app to the alphabetic list
      */
     private void addApp(AppInfo info) {
-        Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
-        int index = Collections.binarySearch(mApps, info, appNameComparator);
+        int index = Collections.binarySearch(mApps, info, mAppNameComparator.getComparator());
         if (index < 0) {
             mApps.add(-(index + 1), info);
             onAppsUpdated();
@@ -220,28 +310,39 @@
      * Updates internals when the set of apps are updated.
      */
     private void onAppsUpdated() {
-        // Recreate the filtered apps
+        // Recreate the filtered and sectioned apps (for convenience for the grid layout)
         mFilteredApps.clear();
-        for (AppInfo info : mApps) {
-            if (mFilter == null || mFilter.retainApp(info)) {
-                mFilteredApps.add(info);
-            }
-        }
-
-        // Section the apps (for convenience for the grid layout)
         mSections.clear();
         mSectionedFilteredApps.clear();
         SectionInfo lastSectionInfo = null;
-        for (AppInfo info : mFilteredApps) {
-            String sectionName = getSectionNameForApp(info);
-            if (lastSectionInfo == null || !lastSectionInfo.sectionName.equals(sectionName)) {
-                lastSectionInfo = new SectionInfo();
-                lastSectionInfo.sectionName = sectionName;
-                mSectionedFilteredApps.add(SECTION_BREAK_INFO);
-                mSections.add(lastSectionInfo);
+        int position = 0;
+        int appIndex = 0;
+        for (AppInfo info : mApps) {
+            String sectionName = mIndexer.computeSectionName(info.title.toString().trim());
+
+            // Check if we want to retain this app
+            if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
+                continue;
             }
+
+            // Create a new section if necessary
+            if (lastSectionInfo == null || !lastSectionInfo.sectionName.equals(sectionName)) {
+                lastSectionInfo = new SectionInfo(sectionName);
+                mSections.add(lastSectionInfo);
+
+                // Create a new section item
+                AdapterItem sectionItem = AdapterItem.asSection(position++, sectionName);
+                mSectionedFilteredApps.add(sectionItem);
+            }
+
+            // Create an app item
+            AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++);
             lastSectionInfo.numAppsInSection++;
-            mSectionedFilteredApps.add(info);
+            if (lastSectionInfo.firstAppItem == null) {
+                lastSectionInfo.firstAppItem = appItem;
+            }
+            mSectionedFilteredApps.add(appItem);
+            mFilteredApps.add(info);
         }
     }
 }
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index b942ea4..c93bacf 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -228,12 +228,12 @@
      * Draws the fast scroller popup.
      */
     private void drawFastScrollerPopup(Canvas canvas) {
-        int x;
-        int y;
-        boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
-                LAYOUT_DIRECTION_RTL);
-
         if (mFastScrollAlpha > 0f) {
+            int x;
+            int y;
+            boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+                    LAYOUT_DIRECTION_RTL);
+
             // Calculate the position for the fast scroller popup
             Rect bgBounds = mFastScrollerBg.getBounds();
             if (isRtl) {
@@ -288,52 +288,50 @@
      */
     private String scrollToPositionAtProgress(float progress) {
         List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections();
-        // Get the total number of rows
-        int rowCount = getNumRows();
+        if (sections.isEmpty()) {
+            return "";
+        }
 
         // Find the position of the first application in the section that contains the row at the
         // current progress
-        int rowAtProgress = (int) (progress * rowCount);
-        int appIndex = 0;
-        rowCount = 0;
-        for (AlphabeticalAppsList.SectionInfo info : sections) {
-            int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow);
-            if (rowCount + numRowsInSection > rowAtProgress) {
+        int rowAtProgress = (int) (progress * getNumRows());
+        int rowCount = 0;
+        AlphabeticalAppsList.SectionInfo lastSectionInfo = null;
+        for (AlphabeticalAppsList.SectionInfo section : sections) {
+            int numRowsInSection = (int) Math.ceil((float) section.numAppsInSection / mNumAppsPerRow);
+            if (rowCount + numRowsInSection >= rowAtProgress) {
+                lastSectionInfo = section;
                 break;
             }
             rowCount += numRowsInSection;
-            appIndex += info.numAppsInSection;
         }
-        appIndex = Math.max(0, Math.min(mApps.getAppsWithoutSectionBreaks().size() - 1, appIndex));
-        AppInfo appInfo = mApps.getAppsWithoutSectionBreaks().get(appIndex);
-        int sectionedAppIndex = mApps.getApps().indexOf(appInfo);
+        int position = mApps.getAdapterItems().indexOf(lastSectionInfo.firstAppItem);
 
         // Scroll the position into view, anchored at the top of the screen if possible. We call the
         // scroll method on the LayoutManager directly since it is not exposed by RecyclerView.
         LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
         stopScroll();
-        layoutManager.scrollToPositionWithOffset(sectionedAppIndex, 0);
+        layoutManager.scrollToPositionWithOffset(position, 0);
 
         // Return the section name of the row
-        return mApps.getSectionNameForApp(appInfo);
+        return mApps.getAdapterItems().get(position).sectionName;
     }
 
     /**
      * Returns the bounds for the scrollbar.
      */
     private void updateVerticalScrollbarBounds() {
-        int x;
-        int y;
-        boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
-                LAYOUT_DIRECTION_RTL);
-
         // Skip early if there are no items
-        if (mApps.getApps().isEmpty()) {
+        if (mApps.getAdapterItems().isEmpty()) {
             mVerticalScrollbarBounds.setEmpty();
             return;
         }
 
         // Find the index and height of the first visible row (all rows have the same height)
+        int x;
+        int y;
+        boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+                LAYOUT_DIRECTION_RTL);
         int rowIndex = -1;
         int rowTopOffset = -1;
         int rowHeight = -1;
@@ -343,10 +341,9 @@
             View child = getChildAt(i);
             int position = getChildPosition(child);
             if (position != NO_POSITION) {
-                AppInfo info = mApps.getApps().get(position);
-                if (info != AlphabeticalAppsList.SECTION_BREAK_INFO) {
-                    int appIndex = mApps.getAppsWithoutSectionBreaks().indexOf(info);
-                    rowIndex = findRowForAppIndex(appIndex);
+                AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
+                if (!item.isSectionHeader) {
+                    rowIndex = findRowForAppIndex(item.appIndex);
                     rowTopOffset = getLayoutManager().getDecoratedTop(child);
                     rowHeight = child.getHeight();
                     break;
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index 06fe93c..2de45cb 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -21,7 +21,6 @@
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.text.Editable;
-import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
@@ -319,9 +318,8 @@
             final String filterText = s.toString().toLowerCase().replaceAll("\\s+", "");
             mApps.setFilter(new AlphabeticalAppsList.Filter() {
                 @Override
-                public boolean retainApp(AppInfo info) {
+                public boolean retainApp(AppInfo info, String sectionName) {
                     String title = info.title.toString();
-                    String sectionName = mApps.getSectionNameForApp(info);
                     return sectionName.toLowerCase().contains(filterText) ||
                             title.toLowerCase().replaceAll("\\s+", "").contains(filterText);
                 }
@@ -332,15 +330,22 @@
     @Override
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
         if (ALLOW_SINGLE_APP_LAUNCH && actionId == EditorInfo.IME_ACTION_DONE) {
-            List<AppInfo> appsWithoutSections = mApps.getAppsWithoutSectionBreaks();
-            List<AppInfo> apps = mApps.getApps();
-            if (appsWithoutSections.size() == 1) {
-                mAppsListView.getChildAt(apps.indexOf(appsWithoutSections.get(0))).performClick();
-                InputMethodManager imm = (InputMethodManager)
-                        getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-                imm.hideSoftInputFromWindow(getWindowToken(), 0);
+            // Skip the quick-launch if there isn't exactly one item
+            if (mApps.getSize() != 1) {
+                return false;
             }
-            return true;
+
+            List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+            for (int i = 0; i < items.size(); i++) {
+                AlphabeticalAppsList.AdapterItem item = items.get(i);
+                if (!item.isSectionHeader) {
+                    mAppsListView.getChildAt(i).performClick();
+                    InputMethodManager imm = (InputMethodManager)
+                            getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(getWindowToken(), 0);
+                    return true;
+                }
+            }
         }
         return false;
     }
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 5895cbf..5b6967c 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -12,9 +12,10 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.util.Thunk;
 
+import java.util.List;
+
 
 /**
  * The grid view adapter of all the apps.
@@ -54,8 +55,7 @@
                 return mAppsPerRow;
             }
 
-            AppInfo info = mApps.getApps().get(position);
-            if (info == AlphabeticalAppsList.SECTION_BREAK_INFO) {
+            if (mApps.getAdapterItems().get(position).isSectionHeader) {
                 // Section break spans full width
                 return mAppsPerRow;
             } else {
@@ -71,6 +71,7 @@
 
         @Override
         public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
             for (int i = 0; i < parent.getChildCount(); i++) {
                 View child = parent.getChildAt(i);
                 ViewHolder holder = (ViewHolder) parent.getChildViewHolder(child);
@@ -78,11 +79,11 @@
                     GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
                             child.getLayoutParams();
                     if (!holder.mIsSectionRow && !holder.mIsEmptyRow && !lp.isItemRemoved()) {
-                        if (mApps.getApps().get(holder.getPosition() - 1) ==
-                                AlphabeticalAppsList.SECTION_BREAK_INFO) {
+                        if (items.get(holder.getPosition() - 1).isSectionHeader) {
                             // Draw at the parent
-                            AppInfo info = mApps.getApps().get(holder.getPosition());
-                            String section = mApps.getSectionNameForApp(info);
+                            AlphabeticalAppsList.AdapterItem item =
+                                    items.get(holder.getPosition());
+                            String section = item.sectionName;
                             mSectionTextPaint.getTextBounds(section, 0, section.length(),
                                     mTmpBounds);
                             if (mIsRtl) {
@@ -212,7 +213,7 @@
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
             case ICON_VIEW_TYPE:
-                AppInfo info = mApps.getApps().get(position);
+                AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
                 break;
@@ -229,14 +230,14 @@
             // For the empty view
             return 1;
         }
-        return mApps.getApps().size();
+        return mApps.getAdapterItems().size();
     }
 
     @Override
     public int getItemViewType(int position) {
         if (mApps.hasNoFilteredResults()) {
             return EMPTY_VIEW_TYPE;
-        } else if (mApps.getApps().get(position) == AlphabeticalAppsList.SECTION_BREAK_INFO) {
+        } else if (mApps.getAdapterItems().get(position).isSectionHeader) {
             return SECTION_BREAK_VIEW_TYPE;
         }
         return ICON_VIEW_TYPE;
diff --git a/src/com/android/launcher3/AppsListAdapter.java b/src/com/android/launcher3/AppsListAdapter.java
index e1f4d35..ffd3092 100644
--- a/src/com/android/launcher3/AppsListAdapter.java
+++ b/src/com/android/launcher3/AppsListAdapter.java
@@ -9,7 +9,6 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import com.android.launcher3.compat.AlphabeticIndexCompat;
 
 /**
  * The linear list view adapter for all the apps.
@@ -93,15 +92,16 @@
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
             case ICON_VIEW_TYPE:
-                AppInfo info = mApps.getApps().get(position);
+                AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
                 ViewGroup content = (ViewGroup) holder.mContent;
-                String sectionDescription = mApps.getSectionNameForApp(info);
+                String sectionDescription = item.sectionName;
 
                 // Bind the section header
                 boolean showSectionHeader = true;
                 if (position > 0) {
-                    AppInfo prevInfo = mApps.getApps().get(position - 1);
-                    showSectionHeader = (prevInfo == AlphabeticalAppsList.SECTION_BREAK_INFO);
+                    AlphabeticalAppsList.AdapterItem prevItem =
+                            mApps.getAdapterItems().get(position - 1);
+                    showSectionHeader = prevItem.isSectionHeader;
                 }
                 TextView tv = (TextView) content.findViewById(R.id.section);
                 if (showSectionHeader) {
@@ -113,7 +113,7 @@
 
                 // Bind the icon
                 BubbleTextView icon = (BubbleTextView) content.getChildAt(1);
-                icon.applyFromApplicationInfo(info);
+                icon.applyFromApplicationInfo(item.appInfo);
                 break;
             case EMPTY_VIEW_TYPE:
                 TextView emptyViewText = (TextView) holder.mContent.findViewById(R.id.empty_text);
@@ -128,14 +128,14 @@
             // For the empty view
             return 1;
         }
-        return mApps.getApps().size();
+        return mApps.getAdapterItems().size();
     }
 
     @Override
     public int getItemViewType(int position) {
         if (mApps.hasNoFilteredResults()) {
             return EMPTY_VIEW_TYPE;
-        } else if (mApps.getApps().get(position) == AlphabeticalAppsList.SECTION_BREAK_INFO) {
+        } else if (mApps.getAdapterItems().get(position).isSectionHeader) {
             return SECTION_BREAK_VIEW_TYPE;
         }
         return ICON_VIEW_TYPE;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 50549ca..ae6ebba 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -389,11 +389,6 @@
     }
 
     @Override
-    protected boolean onSetAlpha(int alpha) {
-        return true;
-    }
-
-    @Override
     public void cancelLongPress() {
         super.cancelLongPress();
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2d07b84..331695a 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -781,7 +781,8 @@
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
             lp.height = hotseatBarHeightPx;
-            hotseat.setPadding(2 * edgeMarginPx, 0, 2 * edgeMarginPx, 0);
+            hotseat.findViewById(R.id.layout).setPadding(2 * edgeMarginPx, 0,
+                    2 * edgeMarginPx, 0);
         }
         hotseat.setLayoutParams(lp);
 
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
index ab21c90..ecf93e4 100644
--- a/src/com/android/launcher3/FocusIndicatorView.java
+++ b/src/com/android/launcher3/FocusIndicatorView.java
@@ -149,7 +149,7 @@
     }
 
     /**
-     * Computes the location of a view relative to {@link #mCommonParent}, off-setting
+     * Computes the location of a view relative to {@param parent}, off-setting
      * any shift due to page view scroll.
      * @param pos an array of two integers in which to hold the coordinates
      */
@@ -166,12 +166,12 @@
     private static void computeLocationRelativeToParentHelper(View child,
             View commonParent, int[] shift) {
         View parent = (View) child.getParent();
-        if (parent instanceof PagedView) {
-            child = ((PagedView) parent).getPageAt(0);
-        }
-
         shift[0] += child.getLeft();
         shift[1] += child.getTop();
+        if (parent instanceof PagedView) {
+            PagedView page = (PagedView) parent;
+            shift[0] -= page.getScrollForPage(page.indexOfChild(child));
+        }
 
         if (parent != commonParent) {
             computeLocationRelativeToParentHelper(parent, commonParent, shift);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 9b2119e..f4af7f5 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -49,6 +49,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map.Entry;
 
 /**
@@ -200,7 +201,7 @@
                     PackageManager.GET_UNINSTALLED_PACKAGES);
             long userSerial = mUserManager.getSerialNumberForUser(user);
             for (LauncherActivityInfoCompat app : mLauncherApps.getActivityList(packageName, user)) {
-                addIconToDB(app, info, userSerial);
+                addIconToDBAndMemCache(app, info, userSerial);
             }
         } catch (NameNotFoundException e) {
             Log.d(TAG, "Package not found", e);
@@ -225,6 +226,7 @@
      * @return The set of packages for which icons have updated.
      */
     public HashSet<String> updateDBIcons(UserHandleCompat user, List<LauncherActivityInfoCompat> apps) {
+        mIconDb.updateSystemStateString(mContext);
         long userSerial = mUserManager.getSerialNumberForUser(user);
         PackageManager pm = mContext.getPackageManager();
         HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
@@ -239,7 +241,8 @@
 
         Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME,
                 new String[] {IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
-                    IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION},
+                    IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
+                    IconDB.COLUMN_SYSTEM_STATE},
                 IconDB.COLUMN_USER + " = ? ",
                 new String[] {Long.toString(userSerial)},
                 null, null, null);
@@ -248,6 +251,7 @@
         final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
         final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
         final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
+        final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
 
         HashSet<Integer> itemsToRemove = new HashSet<Integer>();
         HashSet<String> updatedPackages = new HashSet<String>();
@@ -268,7 +272,8 @@
             long updateTime = c.getLong(indexLastUpdate);
             int version = c.getInt(indexVersion);
             LauncherActivityInfoCompat app = componentMap.remove(component);
-            if (version == info.versionCode && updateTime == info.lastUpdateTime) {
+            if (version == info.versionCode && updateTime == info.lastUpdateTime &&
+                    TextUtils.equals(mIconDb.mSystemState, c.getString(systemStateIndex))) {
                 continue;
             }
             if (app == null) {
@@ -295,14 +300,25 @@
             if (info == null) {
                 continue;
             }
-            addIconToDB(app, info, userSerial);
+            addIconToDBAndMemCache(app, info, userSerial);
         }
         return updatedPackages;
     }
 
-    private void addIconToDB(LauncherActivityInfoCompat app, PackageInfo info, long userSerial) {
+    private void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
+            long userSerial) {
         ContentValues values = updateCacheAndGetContentValues(app);
+        addIconToDB(values, app.getComponentName(), info, userSerial);
         values.put(IconDB.COLUMN_COMPONENT, app.getComponentName().flattenToString());
+    }
+
+    /**
+     * Updates {@param values} to contain versoning information and adds it to the DB.
+     * @param values {@link ContentValues} containing icon & title
+     */
+    private void addIconToDB(ContentValues values, ComponentName key,
+            PackageInfo info, long userSerial) {
+        values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
         values.put(IconDB.COLUMN_USER, userSerial);
         values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime);
         values.put(IconDB.COLUMN_VERSION, info.versionCode);
@@ -320,7 +336,6 @@
         return mIconDb.newContentValues(entry.icon, entry.title.toString());
     }
 
-
     /**
      * Empty out the cache.
      */
@@ -435,6 +450,18 @@
         shortcutInfo.usingLowResIcon = entry.isLowResIcon;
     }
 
+    /**
+     * Fill in {@param appInfo} with the icon and label for {@param packageName}
+     */
+    public synchronized void getTitleAndIconForApp(
+            String packageName, UserHandleCompat user, boolean useLowResIcon, AppInfo appInfoOut) {
+        CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon);
+        appInfoOut.iconBitmap = entry.icon;
+        appInfoOut.title = entry.title;
+        appInfoOut.usingLowResIcon = entry.isLowResIcon;
+        appInfoOut.contentDescription = entry.contentDescription;
+    }
+
     public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
         if (!mDefaultIcons.containsKey(user)) {
             mDefaultIcons.put(user, makeDefaultIcon(user));
@@ -464,8 +491,8 @@
                     entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
                 } else {
                     if (usePackageIcon) {
-                        CacheEntry packageEntry = getEntryForPackage(
-                                componentName.getPackageName(), user);
+                        CacheEntry packageEntry = getEntryForPackageLocked(
+                                componentName.getPackageName(), user, false);
                         if (packageEntry != null) {
                             if (DEBUG) Log.d(TAG, "using package default icon for " +
                                     componentName.toShortString());
@@ -498,7 +525,7 @@
             Bitmap icon, CharSequence title) {
         removeFromMemCacheLocked(packageName, user);
 
-        CacheEntry entry = getEntryForPackage(packageName, user);
+        CacheEntry entry = getEntryForPackageLocked(packageName, user, false);
         if (!TextUtils.isEmpty(title)) {
             entry.title = title;
         }
@@ -510,24 +537,41 @@
     /**
      * Gets an entry for the package, which can be used as a fallback entry for various components.
      * This method is not thread safe, it must be called from a synchronized method.
+     *
      */
-    private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) {
-        ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME);;
+    private CacheEntry getEntryForPackageLocked(String packageName, UserHandleCompat user,
+            boolean useLowResIcon) {
+        ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME);
         ComponentKey cacheKey = new ComponentKey(cn, user);
         CacheEntry entry = mCache.get(cacheKey);
-        if (entry == null) {
+        if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
             entry = new CacheEntry();
-            entry.title = "";
-            entry.contentDescription = "";
             mCache.put(cacheKey, entry);
 
-            try {
-                ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
-                entry.icon = Utilities.createIconBitmap(info.loadIcon(mPackageManager), mContext);
-                entry.title = info.loadLabel(mPackageManager);
-                entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
-            } catch (NameNotFoundException e) {
-                if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+            // Check the DB first.
+            if (!getEntryFromDB(cn, user, entry, useLowResIcon)) {
+                try {
+                    PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
+                    ApplicationInfo appInfo = info.applicationInfo;
+                    if (appInfo == null) {
+                        throw new NameNotFoundException("ApplicationInfo is null");
+                    }
+                    Drawable drawable = mUserManager.getBadgedDrawableForUser(
+                            appInfo.loadIcon(mPackageManager), user);
+                    entry.icon = Utilities.createIconBitmap(drawable, mContext);
+                    entry.title = appInfo.loadLabel(mPackageManager);
+                    entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
+                    entry.isLowResIcon = false;
+
+                    // Add the icon in the DB here, since these do not get written during
+                    // package updates.
+                    ContentValues values =
+                            mIconDb.newContentValues(entry.icon, entry.title.toString());
+                    addIconToDB(values, cn, info, mUserManager.getSerialNumberForUser(user));
+
+                } catch (NameNotFoundException e) {
+                    if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+                }
             }
         }
         return entry;
@@ -605,7 +649,7 @@
     }
 
     private static final class IconDB extends SQLiteOpenHelper {
-        private final static int DB_VERSION = 2;
+        private final static int DB_VERSION = 3;
 
         private final static String TABLE_NAME = "icons";
         private final static String COLUMN_ROWID = "rowid";
@@ -616,11 +660,21 @@
         private final static String COLUMN_ICON = "icon";
         private final static String COLUMN_ICON_LOW_RES = "icon_low_res";
         private final static String COLUMN_LABEL = "label";
+        private final static String COLUMN_SYSTEM_STATE = "system_state";
+
+        public String mSystemState;
 
         public IconDB(Context context) {
             super(context, LauncherFiles.APP_ICONS_DB, null, DB_VERSION);
+            updateSystemStateString(context);
         }
 
+        public void updateSystemStateString(Context c) {
+            mSystemState = Locale.getDefault().toString() + ","
+                    + c.getResources().getConfiguration().mcc;
+        }
+
+
         @Override
         public void onCreate(SQLiteDatabase db) {
             db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
@@ -631,6 +685,7 @@
                     COLUMN_ICON + " BLOB, " +
                     COLUMN_ICON_LOW_RES + " BLOB, " +
                     COLUMN_LABEL + " TEXT, " +
+                    COLUMN_SYSTEM_STATE + " TEXT, " +
                     "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
                     ");");
         }
@@ -656,12 +711,13 @@
 
         public ContentValues newContentValues(Bitmap icon, String label) {
             ContentValues values = new ContentValues();
-            values.put(IconDB.COLUMN_ICON, Utilities.flattenBitmap(icon));
-            values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(
+            values.put(COLUMN_ICON, Utilities.flattenBitmap(icon));
+            values.put(COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(
                     Bitmap.createScaledBitmap(icon,
                             icon.getWidth() / LOW_RES_SCALE_FACTOR,
                             icon.getHeight() / LOW_RES_SCALE_FACTOR, true)));
-            values.put(IconDB.COLUMN_LABEL, label);
+            values.put(COLUMN_LABEL, label);
+            values.put(COLUMN_SYSTEM_STATE, mSystemState);
             return values;
         }
     }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c040d93..2fa2f4a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2958,14 +2958,11 @@
                         sClipRevealMethod = null;
                     }
                 }
-                if (opts == null) {
-                    opts = Utilities.isLmpOrAbove() ?
-                            ActivityOptions.makeCustomAnimation(this,
-                                    R.anim.task_open_enter, R.anim.no_anim) :
-                            ActivityOptions.makeScaleUpAnimation(v, 0, 0,
+                if (opts == null && !Utilities.isLmpOrAbove()) {
+                    opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
                                     v.getMeasuredWidth(), v.getMeasuredHeight());
                 }
-                optsBundle = opts.toBundle();
+                optsBundle = opts != null ? opts.toBundle() : null;
             }
 
             if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index c6ed0da..1f36331 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -3622,41 +3622,6 @@
         return folderInfo;
     }
 
-    public static final Comparator<AppInfo> getAppNameComparator() {
-        final Collator collator = Collator.getInstance();
-        return new Comparator<AppInfo>() {
-            public final int compare(AppInfo a, AppInfo b) {
-                if (a.user.equals(b.user)) {
-                    int result = collator.compare(a.title.toString().trim(),
-                            b.title.toString().trim());
-                    if (result == 0) {
-                        result = a.componentName.compareTo(b.componentName);
-                    }
-                    return result;
-                } else {
-                    // TODO Need to figure out rules for sorting
-                    // profiles, this puts work second.
-                    return a.user.toString().compareTo(b.user.toString());
-                }
-            }
-        };
-    }
-    public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR
-            = new Comparator<AppInfo>() {
-        public final int compare(AppInfo a, AppInfo b) {
-            if (a.firstInstallTime < b.firstInstallTime) return 1;
-            if (a.firstInstallTime > b.firstInstallTime) return -1;
-            return 0;
-        }
-    };
-    static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
-        if (info.activityInfo != null) {
-            return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
-        } else {
-            return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
-        }
-    }
-
     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
         private final AppWidgetManagerCompat mManager;
         private final PackageManager mPackageManager;
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index a23553a..1f59533 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -341,8 +341,11 @@
         Context ctx = getContext();
         UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
         Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
-        String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
+        if (bundle == null) {
+            return null;
+        }
 
+        String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
         if (packageName != null) {
             try {
                 Resources targetResources = ctx.getPackageManager()
diff --git a/src/com/android/launcher3/PackageChangedReceiver.java b/src/com/android/launcher3/PackageChangedReceiver.java
deleted file mode 100644
index b98f472..0000000
--- a/src/com/android/launcher3/PackageChangedReceiver.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.android.launcher3;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-// TODO: Remove this
-public class PackageChangedReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(final Context context, Intent intent) {
-
-    }
-}
diff --git a/src/com/android/launcher3/UninstallShortcutReceiver.java b/src/com/android/launcher3/UninstallShortcutReceiver.java
deleted file mode 100644
index 59e4cb5..0000000
--- a/src/com/android/launcher3/UninstallShortcutReceiver.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-//TODO: Remove this
-public class UninstallShortcutReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent data) { }
-}
diff --git a/src/com/android/launcher3/UserInitializeReceiver.java b/src/com/android/launcher3/UserInitializeReceiver.java
deleted file mode 100644
index d8e17b1..0000000
--- a/src/com/android/launcher3/UserInitializeReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 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;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Takes care of setting initial wallpaper for a user, by selecting the
- * first wallpaper that is not in use by another user.
- */
-public class UserInitializeReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // TODO: initial wallpaper now that wallpapers are owned by another app
-    }
-}