Merge "Enables direct scrolling on the fastscroll bar." into ub-launcher3-master
diff --git a/build.gradle b/build.gradle
index 4d700c5..00667f1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,12 +12,12 @@
 apply plugin: 'com.google.protobuf'
 
 android {
-    compileSdkVersion 25
+    compileSdkVersion 26
     buildToolsVersion '24.0.0'
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 25
+        targetSdkVersion 26
         versionCode 1
         versionName "1.0"
 
@@ -59,10 +59,11 @@
     mavenCentral()
 }
 
+final String SUPPORT_LIBS_VERSION = '26.0.0-SNAPSHOT'
 dependencies {
-    compile 'com.android.support:support-v4:23.1.1'
-    compile 'com.android.support:recyclerview-v7:23.1.1'
-    compile 'com.android.support:palette-v7:23.2.0'
+    compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
+    compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
+    compile "com.android.support:palette-v7:${SUPPORT_LIBS_VERSION}"
     compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-2'
 
     testCompile 'junit:junit:4.12'
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index f7c5184..9c9dcc5 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -19,7 +19,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -33,23 +32,13 @@
 /**
  * Represents an app in AllAppsView.
  */
-public class AppInfo extends ItemInfo {
+public class AppInfo extends ItemInfoWithIcon {
 
     /**
      * The intent used to start the application.
      */
     public Intent intent;
 
-    /**
-     * A bitmap version of the application icon.
-     */
-    public Bitmap iconBitmap;
-
-    /**
-     * Indicates whether we're using a low res icon
-     */
-    boolean usingLowResIcon;
-
     public ComponentName componentName;
 
     /**
@@ -66,10 +55,6 @@
         return intent;
     }
 
-    protected Intent getRestoredIntent() {
-        return null;
-    }
-
     /**
      * Must not hold the Context.
      */
@@ -96,8 +81,8 @@
             isDisabled |= ShortcutInfo.FLAG_DISABLED_QUIET_USER;
         }
 
-        iconCache.getTitleAndIcon(this, info, useLowResIcon);
         intent = makeLaunchIntent(context, info, user);
+        iconCache.getTitleAndIcon(this, info, useLowResIcon);
     }
 
     public AppInfo(AppInfo info) {
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 54faca3..f879216 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -354,8 +354,7 @@
     }
 
     public void snapToWidget(boolean animate) {
-        DeviceProfile profile = mLauncher.getDeviceProfile();
-        float scale = Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+        float scale = mWidgetView.getScaleToFit();
 
         mDragLayer.getViewRectRelativeToSelf(mWidgetView, sTmpRect);
 
@@ -519,10 +518,10 @@
         public int applyDeltaAndBound(boolean moveStart, boolean moveEnd, int delta,
                 int minSize, int maxEnd, IntRange out) {
             applyDelta(moveStart, moveEnd, delta, out);
-            if (start < 0) {
+            if (out.start < 0) {
                 out.start = 0;
             }
-            if (end > maxEnd) {
+            if (out.end > maxEnd) {
                 out.end = maxEnd;
             }
             if (out.size() < minSize) {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 0c1a156..5e9e7e2 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -524,11 +524,7 @@
 
     protected void applyCompoundDrawables(Drawable icon) {
         if (mLayoutHorizontal) {
-            if (Utilities.ATLEAST_JB_MR1) {
-                setCompoundDrawablesRelative(icon, null, null, null);
-            } else {
-                setCompoundDrawables(icon, null, null, null);
-            }
+            setCompoundDrawablesRelative(icon, null, null, null);
         } else {
             setCompoundDrawables(null, icon, null, null);
         }
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index e613b3b..85b08d1 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -21,7 +21,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -30,7 +29,6 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -100,17 +98,11 @@
         mOriginalTextColor = getTextColors();
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     protected void setDrawable(int resId) {
         // We do not set the drawable in the xml as that inflates two drawables corresponding to
         // drawableLeft and drawableStart.
         mDrawable = getResources().getDrawable(resId);
-
-        if (Utilities.ATLEAST_JB_MR1) {
-            setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
-        } else {
-            setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null, null);
-        }
+        setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
     }
 
     public void setDropTargetBar(DropTargetBar dropTargetBar) {
@@ -120,16 +112,7 @@
     @Override
     public final void onDragEnter(DragObject d) {
         d.dragView.setColor(mHoverColor);
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            animateTextColor(mHoverColor);
-        } else {
-            if (mCurrentFilter == null) {
-                mCurrentFilter = new ColorMatrix();
-            }
-            DragView.setColorScale(mHoverColor, mCurrentFilter);
-            mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
-            setTextColor(mHoverColor);
-        }
+        animateTextColor(mHoverColor);
         if (d.stateAnnouncer != null) {
             d.stateAnnouncer.cancel();
         }
@@ -142,15 +125,9 @@
     }
 
     protected void resetHoverColor() {
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            animateTextColor(mOriginalTextColor.getDefaultColor());
-        } else {
-            mDrawable.setColorFilter(null);
-            setTextColor(mOriginalTextColor);
-        }
+        animateTextColor(mOriginalTextColor.getDefaultColor());
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void animateTextColor(int targetColor) {
         if (mCurrentColorAnim != null) {
             mCurrentColorAnim.cancel();
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 1e212bf..70c8739 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -21,7 +21,6 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -33,7 +32,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Parcelable;
 import android.support.annotation.IntDef;
 import android.support.v4.view.ViewCompat;
@@ -297,7 +295,6 @@
         addView(mShortcutsAndWidgets);
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public void enableAccessibleDrag(boolean enable, int dragType) {
         mUseTouchHelper = enable;
         if (!enable) {
@@ -1975,6 +1972,8 @@
         private static final int PREVIEW_DURATION = 300;
         private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT;
 
+        private static final float CHILD_DIVIDEND = 4.0f;
+
         public static final int MODE_HINT = 0;
         public static final int MODE_PREVIEW = 1;
 
@@ -1990,42 +1989,62 @@
             final int y1 = mTmpPoint[1];
             final int dX = x1 - x0;
             final int dY = y1 - y0;
-            finalDeltaX = 0;
-            finalDeltaY = 0;
+
+            this.child = child;
+            this.mode = mode;
+            setInitialAnimationValues(false);
+            finalScale = (mChildScale - (CHILD_DIVIDEND / child.getWidth())) * initScale;
+            finalDeltaX = initDeltaX;
+            finalDeltaY = initDeltaY;
             int dir = mode == MODE_HINT ? -1 : 1;
             if (dX == dY && dX == 0) {
             } else {
                 if (dY == 0) {
-                    finalDeltaX = - dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
+                    finalDeltaX += - dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
                 } else if (dX == 0) {
-                    finalDeltaY = - dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
+                    finalDeltaY += - dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
                 } else {
                     double angle = Math.atan( (float) (dY) / dX);
-                    finalDeltaX = (int) (- dir * Math.signum(dX) *
+                    finalDeltaX += (int) (- dir * Math.signum(dX) *
                             Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
-                    finalDeltaY = (int) (- dir * Math.signum(dY) *
+                    finalDeltaY += (int) (- dir * Math.signum(dY) *
                             Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
                 }
             }
-            this.mode = mode;
-            initDeltaX = child.getTranslationX();
-            initDeltaY = child.getTranslationY();
-            finalScale = mChildScale - 4.0f / child.getWidth();
-            initScale = child.getScaleX();
-            this.child = child;
+        }
+
+        void setInitialAnimationValues(boolean restoreOriginalValues) {
+            if (restoreOriginalValues) {
+                if (child instanceof LauncherAppWidgetHostView) {
+                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
+                    initScale = lahv.getScaleToFit();
+                    initDeltaX = lahv.getTranslationForCentering().x;
+                    initDeltaY = lahv.getTranslationForCentering().y;
+                } else {
+                    initScale = mChildScale;
+                    initDeltaX = 0;
+                    initDeltaY = 0;
+                }
+            } else {
+                initScale = child.getScaleX();
+                initDeltaX = child.getTranslationX();
+                initDeltaY = child.getTranslationY();
+            }
         }
 
         void animate() {
+            boolean noMovement = (finalDeltaX == initDeltaX) && (finalDeltaY == initDeltaY);
+
             if (mShakeAnimators.containsKey(child)) {
                 ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child);
                 oldAnimation.cancel();
                 mShakeAnimators.remove(child);
-                if (finalDeltaX == 0 && finalDeltaY == 0) {
+                if (noMovement) {
                     completeAnimationImmediately();
                     return;
                 }
             }
-            if (finalDeltaX == 0 && finalDeltaY == 0) {
+            if (noMovement) {
                 return;
             }
             ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f);
@@ -2058,9 +2077,7 @@
             va.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationRepeat(Animator animation) {
                     // We make sure to end only after a full period
-                    initDeltaX = 0;
-                    initDeltaY = 0;
-                    initScale = mChildScale;
+                    setInitialAnimationValues(true);
                     repeating = true;
                 }
             });
@@ -2080,10 +2097,10 @@
             }
 
             a = new LauncherViewPropertyAnimator(child)
-                .scaleX(mChildScale)
-                .scaleY(mChildScale)
-                .translationX(0)
-                .translationY(0)
+                .scaleX(initScale)
+                .scaleY(initScale)
+                .translationX(initDeltaX)
+                .translationY(initDeltaY)
                 .setDuration(REORDER_ANIMATION_DURATION);
             a.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
             a.start();
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 3557447..b22cb7c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -41,6 +41,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -51,6 +52,7 @@
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.SQLiteCacheHelper;
 import com.android.launcher3.util.Thunk;
 
@@ -409,16 +411,10 @@
 
             @Override
             public void run() {
-                if (info instanceof AppInfo) {
-                    getTitleAndIcon((AppInfo) info, null, false);
-                } else if (info instanceof ShortcutInfo) {
-                    ShortcutInfo st = (ShortcutInfo) info;
-                    getTitleAndIcon(st,
-                            st.promisedIntent != null ? st.promisedIntent : st.intent,
-                            st.user, false);
+                if (info instanceof AppInfo || info instanceof ShortcutInfo) {
+                    getTitleAndIcon((ItemInfoWithIcon) info, false);
                 } else if (info instanceof PackageItemInfo) {
-                    PackageItemInfo pti = (PackageItemInfo) info;
-                    getTitleAndIconForApp(pti, false);
+                    getTitleAndIconForApp((PackageItemInfo) info, false);
                 }
                 mMainThreadExecutor.execute(new Runnable() {
 
@@ -433,38 +429,6 @@
         return new IconLoadRequest(request, mWorkerHandler);
     }
 
-    private Bitmap getNonNullIcon(CacheEntry entry, UserHandle user) {
-        return entry.icon == null ? getDefaultIcon(user) : entry.icon;
-    }
-
-    /**
-     * Fill in "application" with the icon and label for "info."
-     */
-    public synchronized void getTitleAndIcon(AppInfo application,
-            LauncherActivityInfoCompat info, boolean useLowResIcon) {
-        UserHandle user = info == null ? application.user : info.getUser();
-        CacheEntry entry = cacheLocked(application.componentName, info, user,
-                false, useLowResIcon);
-        application.title = Utilities.trim(entry.title);
-        application.contentDescription = entry.contentDescription;
-        application.iconBitmap = getNonNullIcon(entry, user);
-        application.usingLowResIcon = entry.isLowResIcon;
-    }
-
-    /**
-     * Updates {@param application} only if a valid entry is found.
-     */
-    public synchronized void updateTitleAndIcon(AppInfo application) {
-        CacheEntry entry = cacheLocked(application.componentName, null, application.user,
-                false, application.usingLowResIcon);
-        if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
-            application.title = Utilities.trim(entry.title);
-            application.contentDescription = entry.contentDescription;
-            application.iconBitmap = entry.icon;
-            application.usingLowResIcon = entry.isLowResIcon;
-        }
-    }
-
     /**
      * Returns a high res icon for the given intent and user
      */
@@ -475,43 +439,59 @@
         if (component == null) {
             return getDefaultIcon(user);
         }
-
-        LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
-        CacheEntry entry = cacheLocked(component, launcherActInfo, user, true, false /* useLowRes */);
-        return entry.icon;
+        return cacheLocked(component, new ActivityInfoProvider(intent, user),
+                user, true, false /* useLowRes */).icon;
     }
 
     /**
-     * Fill in {@param shortcutInfo} with the icon and label for {@param intent}. If the
+     * Updates {@param application} only if a valid entry is found.
+     */
+    public synchronized void updateTitleAndIcon(AppInfo application) {
+        CacheEntry entry = cacheLocked(application.componentName,
+                Provider.<LauncherActivityInfoCompat>of(null),
+                application.user, false, application.usingLowResIcon);
+        if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
+            applyCacheEntry(entry, application);
+        }
+    }
+
+    /**
+     * Fill in {@param info} with the icon and label for {@param activityInfo}
+     */
+    public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
+            LauncherActivityInfoCompat activityInfo, boolean useLowResIcon) {
+        // If we already have activity info, no need to use package icon
+        getTitleAndIcon(info, Provider.of(activityInfo), false, useLowResIcon);
+    }
+
+    /**
+     * Fill in {@param info} with the icon and label. If the
      * corresponding activity is not found, it reverts to the package icon.
      */
-    public synchronized void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent,
-            UserHandle user, boolean useLowResIcon) {
-        ComponentName component = intent.getComponent();
+    public synchronized void getTitleAndIcon(ItemInfoWithIcon info, boolean useLowResIcon) {
         // null info means not installed, but if we have a component from the intent then
         // we should still look in the cache for restored app icons.
-        if (component == null) {
-            shortcutInfo.iconBitmap = getDefaultIcon(user);
-            shortcutInfo.title = "";
-            shortcutInfo.contentDescription = "";
-            shortcutInfo.usingLowResIcon = false;
+        if (info.getTargetComponent() == null) {
+            info.iconBitmap = getDefaultIcon(info.user);
+            info.title = "";
+            info.contentDescription = "";
+            info.usingLowResIcon = false;
         } else {
-            LauncherActivityInfoCompat info = mLauncherApps.resolveActivity(intent, user);
-            getTitleAndIcon(shortcutInfo, component, info, user, true, useLowResIcon);
+            getTitleAndIcon(info, new ActivityInfoProvider(info.getIntent(), info.user),
+                    true, useLowResIcon);
         }
     }
 
     /**
      * Fill in {@param shortcutInfo} with the icon and label for {@param info}
      */
-    public synchronized void getTitleAndIcon(
-            ShortcutInfo shortcutInfo, ComponentName component, LauncherActivityInfoCompat info,
-            UserHandle user, boolean usePkgIcon, boolean useLowResIcon) {
-        CacheEntry entry = cacheLocked(component, info, user, usePkgIcon, useLowResIcon);
-        shortcutInfo.iconBitmap = getNonNullIcon(entry, user);
-        shortcutInfo.title = Utilities.trim(entry.title);
-        shortcutInfo.contentDescription = entry.contentDescription;
-        shortcutInfo.usingLowResIcon = entry.isLowResIcon;
+    private synchronized void getTitleAndIcon(
+            @NonNull ItemInfoWithIcon infoInOut,
+            @NonNull Provider<LauncherActivityInfoCompat> activityInfoProvider,
+            boolean usePkgIcon, boolean useLowResIcon) {
+        CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), activityInfoProvider,
+                infoInOut.user, usePkgIcon, useLowResIcon);
+        applyCacheEntry(entry, infoInOut);
     }
 
     /**
@@ -521,10 +501,14 @@
             PackageItemInfo infoInOut, boolean useLowResIcon) {
         CacheEntry entry = getEntryForPackageLocked(
                 infoInOut.packageName, infoInOut.user, useLowResIcon);
-        infoInOut.title = Utilities.trim(entry.title);
-        infoInOut.contentDescription = entry.contentDescription;
-        infoInOut.iconBitmap = getNonNullIcon(entry, infoInOut.user);
-        infoInOut.usingLowResIcon = entry.isLowResIcon;
+        applyCacheEntry(entry, infoInOut);
+    }
+
+    private void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
+        info.title = Utilities.trim(entry.title);
+        info.contentDescription = entry.contentDescription;
+        info.iconBitmap = entry.icon == null ? getDefaultIcon(info.user) : entry.icon;
+        info.usingLowResIcon = entry.isLowResIcon;
     }
 
     public synchronized Bitmap getDefaultIcon(UserHandle user) {
@@ -542,7 +526,9 @@
      * Retrieves the entry from the cache. If the entry is not present, it creates a new entry.
      * This method is not thread safe, it must be called from a synchronized method.
      */
-    protected CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info,
+    protected CacheEntry cacheLocked(
+            @NonNull ComponentName componentName,
+            @NonNull Provider<LauncherActivityInfoCompat> infoProfider,
             UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
         ComponentKey cacheKey = new ComponentKey(componentName, user);
         CacheEntry entry = mCache.get(cacheKey);
@@ -551,7 +537,13 @@
             mCache.put(cacheKey, entry);
 
             // Check the DB first.
+            LauncherActivityInfoCompat info = null;
+            boolean providerFetchedOnce = false;
+
             if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
+                info = infoProfider.get();
+                providerFetchedOnce = true;
+
                 if (info != null) {
                     entry.icon = LauncherIcons.createBadgedIconBitmap(
                             mIconProvider.getIcon(info, mIconDpi), info.getUser(),
@@ -576,9 +568,15 @@
                 }
             }
 
-            if (TextUtils.isEmpty(entry.title) && info != null) {
-                entry.title = info.getLabel();
-                entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
+            if (TextUtils.isEmpty(entry.title)) {
+                if (info == null && !providerFetchedOnce) {
+                    info = infoProfider.get();
+                    providerFetchedOnce = true;
+                }
+                if (info != null) {
+                    entry.title = info.getLabel();
+                    entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
+                }
             }
         }
         return entry;
@@ -668,37 +666,6 @@
         return entry;
     }
 
-    /**
-     * Pre-load an icon into the persistent cache.
-     *
-     * <P>Queries for a component that does not exist in the package manager
-     * will be answered by the persistent cache.
-     *
-     * @param componentName the icon should be returned for this component
-     * @param icon the icon to be persisted
-     * @param dpi the native density of the icon
-     */
-    public void preloadIcon(ComponentName componentName, Bitmap icon, int dpi, String label,
-            long userSerial, InvariantDeviceProfile idp) {
-        // TODO rescale to the correct native DPI
-        try {
-            PackageManager packageManager = mContext.getPackageManager();
-            packageManager.getActivityIcon(componentName);
-            // component is present on the system already, do nothing
-            return;
-        } catch (PackageManager.NameNotFoundException e) {
-            // pass
-        }
-
-        icon = Bitmap.createScaledBitmap(icon, idp.iconBitmapSize, idp.iconBitmapSize, true);
-        Bitmap lowResIcon = generateLowResIcon(icon, Color.TRANSPARENT);
-        ContentValues values = newContentValues(icon, lowResIcon, label,
-                componentName.getPackageName());
-        values.put(IconDB.COLUMN_COMPONENT, componentName.flattenToString());
-        values.put(IconDB.COLUMN_USER, userSerial);
-        mIconDb.insertOrReplace(values);
-    }
-
     private boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
         Cursor c = null;
         try {
@@ -885,4 +852,20 @@
             return null;
         }
     }
+
+    private class ActivityInfoProvider extends Provider<LauncherActivityInfoCompat> {
+
+        private final Intent mIntent;
+        private final UserHandle mUser;
+
+        public ActivityInfoProvider(Intent intent, UserHandle user) {
+            mIntent = intent;
+            mUser = user;
+        }
+
+        @Override
+        public LauncherActivityInfoCompat get() {
+            return mLauncherApps.resolveActivity(mIntent, mUser);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index 6a6d285..db14e2e 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -18,7 +18,6 @@
 
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -90,13 +89,12 @@
 
     @Override
     protected boolean supportsDrop(DragSource source, ItemInfo info) {
-        return source.supportsAppInfoDropTarget() && supportsDrop(info);
+        return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
     }
 
-    public static boolean supportsDrop(ItemInfo info) {
+    public static boolean supportsDrop(Context context, ItemInfo info) {
         // Only show the App Info drop target if developer settings are enabled.
-        ContentResolver resolver = LauncherAppState.getInstance().getContext().getContentResolver();
-        boolean developmentSettingsEnabled = Settings.Global.getInt(resolver,
+        boolean developmentSettingsEnabled = Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
         return developmentSettingsEnabled
                 && (info instanceof AppInfo || info instanceof ShortcutInfo
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
new file mode 100644
index 0000000..a3d8c6a
--- /dev/null
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+import android.graphics.Bitmap;
+
+/**
+ * Represents an ItemInfo which also holds an icon.
+ */
+public abstract class ItemInfoWithIcon extends ItemInfo {
+
+    /**
+     * A bitmap version of the application icon.
+     */
+    public Bitmap iconBitmap;
+
+    /**
+     * Indicates whether we're using a low res icon
+     */
+    public boolean usingLowResIcon;
+
+    protected ItemInfoWithIcon() { }
+
+    protected ItemInfoWithIcon(ItemInfo info) {
+        super(info);
+    }
+}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 08f56d1..8e28912 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -44,7 +44,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -69,7 +68,6 @@
 import android.view.KeyboardShortcutInfo;
 import android.view.Menu;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.View;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
@@ -89,7 +87,6 @@
 import com.android.launcher3.allapps.DefaultAppSearchController;
 import com.android.launcher3.anim.AnimationLayerSet;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
@@ -738,7 +735,7 @@
             } else if (resultCode == RESULT_OK) {
                 addAppWidgetImpl(
                         appWidgetId, requestArgs, null,
-                        requestArgs.getWidgetProvider(),
+                        requestArgs.getWidgetProvider(this),
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY);
             }
             return;
@@ -897,7 +894,7 @@
         if (resultCode == RESULT_OK) {
             animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
             final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
-                    requestArgs.getWidgetProvider());
+                    requestArgs.getWidgetProvider(this));
             boundWidget = layout;
             onCompleteRunnable = new Runnable() {
                 @Override
@@ -1507,7 +1504,7 @@
         launcherInfo.spanY = itemInfo.spanY;
         launcherInfo.minSpanX = itemInfo.minSpanX;
         launcherInfo.minSpanY = itemInfo.minSpanY;
-        launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo);
+        launcherInfo.user = appWidgetInfo.getUser();
 
         LauncherModel.addItemToDatabase(this, launcherInfo,
                 itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY);
@@ -2090,7 +2087,7 @@
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                        mAppWidgetManager.getUser(info.info));
+                        info.info.getUser());
                 // TODO: we need to make sure that this accounts for the options bundle.
                 // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
                 startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
@@ -2324,7 +2321,7 @@
                     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
                     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, appWidgetInfo.provider);
                     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                            mAppWidgetManager.getUser(appWidgetInfo));
+                            appWidgetInfo.getUser());
                     startActivityForResult(intent, REQUEST_BIND_PENDING_APPWIDGET);
                 }
             } else {
@@ -3483,7 +3480,7 @@
 
                     // Also try to bind the widget. If the bind fails, the user will be shown
                     // a click to setup UI, which will ask for the bind permission.
-                    PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo);
+                    PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo);
                     pendingInfo.spanX = item.spanX;
                     pendingInfo.spanY = item.spanY;
                     pendingInfo.minSpanX = item.minSpanX;
@@ -3802,7 +3799,7 @@
 
             for (ShortcutInfo si : removed) {
                 if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                    removedDeepShortcuts.add(ShortcutKey.fromShortcutInfo(si));
+                    removedDeepShortcuts.add(ShortcutKey.fromItemInfo(si));
                 } else {
                     removedComponents.add(si.getTargetComponent());
                 }
@@ -3916,47 +3913,9 @@
         }
     }
 
-    private int mapConfigurationOriActivityInfoOri(int configOri) {
-        final Display d = getWindowManager().getDefaultDisplay();
-        int naturalOri = Configuration.ORIENTATION_LANDSCAPE;
-        switch (d.getRotation()) {
-        case Surface.ROTATION_0:
-        case Surface.ROTATION_180:
-            // We are currently in the same basic orientation as the natural orientation
-            naturalOri = configOri;
-            break;
-        case Surface.ROTATION_90:
-        case Surface.ROTATION_270:
-            // We are currently in the other basic orientation to the natural orientation
-            naturalOri = (configOri == Configuration.ORIENTATION_LANDSCAPE) ?
-                    Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
-            break;
-        }
-
-        int[] oriMap = {
-                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
-                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
-                ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
-                ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
-        };
-        // Since the map starts at portrait, we need to offset if this device's natural orientation
-        // is landscape.
-        int indexOffset = 0;
-        if (naturalOri == Configuration.ORIENTATION_LANDSCAPE) {
-            indexOffset = 1;
-        }
-        return oriMap[(d.getRotation() + indexOffset) % 4];
-    }
-
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     public void lockScreenOrientation() {
         if (mRotationEnabled) {
-            if (Utilities.ATLEAST_JB_MR2) {
-                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
-            } else {
-                setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
-                        .getConfiguration().orientation));
-            }
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index ca5cd74..00e4bf4 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -42,8 +41,6 @@
     private final IconCache mIconCache;
     private final WidgetPreviewLoader mWidgetCache;
 
-    @Thunk boolean mWallpaperChangedSinceLastCheck;
-
     private static WeakReference<LauncherProvider> sLauncherProvider;
     private static Context sContext;
 
@@ -117,15 +114,6 @@
 
         sContext.registerReceiver(mModel, filter);
         UserManagerCompat.getInstance(sContext).enableAndResetCache();
-        if (!Utilities.ATLEAST_KITKAT) {
-            sContext.registerReceiver(new BroadcastReceiver() {
-
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    mWallpaperChangedSinceLastCheck = true;
-                }
-            }, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
-        }
         new ConfigMonitor(sContext).register();
 
         ExtractionUtils.startColorExtractionServiceIfNecessary(sContext);
@@ -168,12 +156,6 @@
         return mWidgetCache;
     }
 
-    public boolean hasWallpaperChangedSinceLastCheck() {
-        boolean result = mWallpaperChangedSinceLastCheck;
-        mWallpaperChangedSinceLastCheck = false;
-        return result;
-    }
-
     public InvariantDeviceProfile getInvariantDeviceProfile() {
         return mInvariantDeviceProfile;
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 657b024..6e8c59b 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -128,7 +128,7 @@
         super.onProviderChanged(appWidgetId, info);
         // The super method updates the dimensions of the providerInfo. Update the
         // launcher spans accordingly.
-        info.initSpans();
+        info.initSpans(mLauncher);
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index a4ea449..49bbfd0 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -19,6 +19,7 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -72,6 +73,16 @@
     private boolean mIsAutoAdvanceRegistered;
     private Runnable mAutoAdvanceRunnable;
 
+    /**
+     * The scaleX and scaleY value such that the widget fits within its cellspans, scaleX = scaleY.
+     */
+    private float mScaleToFit = 1f;
+
+    /**
+     * The translation values to center the widget within its cellspans.
+     */
+    private final PointF mTranslationForCentering = new PointF(0, 0);
+
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mContext = context;
@@ -415,4 +426,24 @@
         }
         scheduleNextAdvance();
     }
+
+    public void setScaleToFit(float scale) {
+        mScaleToFit = scale;
+        setScaleX(scale);
+        setScaleY(scale);
+    }
+
+    public float getScaleToFit() {
+        return mScaleToFit;
+    }
+
+    public void setTranslationForCentering(float x, float y) {
+        mTranslationForCentering.set(x, y);
+        setTranslationX(x);
+        setTranslationY(y);
+    }
+
+    public PointF getTranslationForCentering() {
+        return mTranslationForCentering;
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 1a4153f..ab8f395 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -1,6 +1,5 @@
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -9,8 +8,9 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Parcel;
+import android.os.Process;
+import android.os.UserHandle;
 
 /**
  * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
@@ -29,22 +29,27 @@
 
     public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
             AppWidgetProviderInfo info) {
+        final LauncherAppWidgetProviderInfo launcherInfo;
+        if (info instanceof LauncherAppWidgetProviderInfo) {
+            launcherInfo = (LauncherAppWidgetProviderInfo) info;
+        } else {
 
-        // In lieu of a public super copy constructor, we first write the AppWidgetProviderInfo
-        // into a parcel, and then construct a new LauncherAppWidgetProvider info from the
-        // associated super parcel constructor. This allows us to copy non-public members without
-        // using reflection.
-        Parcel p = Parcel.obtain();
-        info.writeToParcel(p, 0);
-        p.setDataPosition(0);
-        LauncherAppWidgetProviderInfo lawpi = new LauncherAppWidgetProviderInfo(p);
-        p.recycle();
-        return lawpi;
+            // In lieu of a public super copy constructor, we first write the AppWidgetProviderInfo
+            // into a parcel, and then construct a new LauncherAppWidgetProvider info from the
+            // associated super parcel constructor. This allows us to copy non-public members without
+            // using reflection.
+            Parcel p = Parcel.obtain();
+            info.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            launcherInfo = new LauncherAppWidgetProviderInfo(p);
+            p.recycle();
+        }
+        launcherInfo.initSpans(context);
+        return launcherInfo;
     }
 
-    public LauncherAppWidgetProviderInfo(Parcel in) {
+    private LauncherAppWidgetProviderInfo(Parcel in) {
         super(in);
-        initSpans();
     }
 
     public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) {
@@ -56,12 +61,11 @@
         previewImage = widget.getPreviewImage();
         initialLayout = widget.getWidgetLayout();
         resizeMode = widget.getResizeMode();
-        initSpans();
+        initSpans(context);
     }
 
-    public void initSpans() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
+    public void initSpans(Context context) {
+        InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
 
         Point paddingLand = idp.landscapeProfile.getTotalWorkspacePadding();
         Point paddingPort = idp.portraitProfile.getTotalWorkspacePadding();
@@ -80,7 +84,7 @@
         // We want to account for the extra amount of padding that we are adding to the widget
         // to ensure that it gets the full amount of space that it has requested.
         Rect widgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(
-                app.getContext(), provider, null);
+                context, provider, null);
         spanX = Math.max(1, (int) Math.ceil(
                         (minWidth + widgetPadding.left + widgetPadding.right) / smallestCellWidth));
         spanY = Math.max(1, (int) Math.ceil(
@@ -92,7 +96,6 @@
                 (minResizeHeight + widgetPadding.top + widgetPadding.bottom) / smallestCellHeight));
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public String getLabel(PackageManager packageManager) {
         if (isCustomWidget) {
             return Utilities.trim(label);
@@ -100,7 +103,6 @@
         return super.loadLabel(packageManager);
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public Drawable getIcon(Context context, IconCache cache) {
         if (isCustomWidget) {
             return cache.getFullResIcon(provider.getPackageName(), icon);
@@ -122,4 +124,8 @@
                 (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1,
                         (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1);
     }
+
+    public UserHandle getUser() {
+        return isCustomWidget ? Process.myUserHandle() : getProfile();
+    }
  }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 0dc91e3..58a7495 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1794,8 +1794,7 @@
                     for (ShortcutInfo info : folder.contents) {
                         if (info.usingLowResIcon &&
                                 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                            mIconCache.getTitleAndIcon(
-                                    info, info.getPromisedIntent(), info.user, false);
+                            mIconCache.getTitleAndIcon(info, false);
                         }
                         pos ++;
                         if (pos >= FolderIcon.NUM_ITEMS_IN_PREVIEW) {
@@ -2520,10 +2519,12 @@
             int promiseType, int itemType, CursorIconInfo iconInfo) {
         final ShortcutInfo info = new ShortcutInfo();
         info.user = Process.myUserHandle();
+        info.promisedIntent = intent;
+
         info.iconBitmap = iconInfo.loadIcon(c, info);
         // the fallback icon
         if (info.iconBitmap == null) {
-            mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);
+            mIconCache.getTitleAndIcon(info, false /* useLowResIcon */);
         }
 
         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
@@ -2541,7 +2542,6 @@
 
         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
         info.itemType = itemType;
-        info.promisedIntent = intent;
         info.status = promiseType;
         return info;
     }
@@ -2592,7 +2592,11 @@
         }
 
         final ShortcutInfo info = new ShortcutInfo();
-        mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);
+        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+        info.user = user;
+        info.intent = newIntent;
+
+        mIconCache.getTitleAndIcon(info, lai, useLowResIcon);
         if (mIconCache.isDefaultIcon(info.iconBitmap, user) && c != null) {
             Bitmap icon = iconInfo.loadIcon(c);
             info.iconBitmap = icon != null ? icon : mIconCache.getDefaultIcon(user);
@@ -2612,8 +2616,6 @@
             info.title = componentName.getClassName();
         }
 
-        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-        info.user = user;
         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
         return info;
     }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index c6edae9..8f56eb6 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
@@ -39,7 +38,6 @@
 import android.database.sqlite.SQLiteStatement;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -534,13 +532,7 @@
      *
      * @return the loader if the restrictions are set and the resource exists; null otherwise.
      */
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
-        // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18
-        if (!Utilities.ATLEAST_JB_MR2) {
-            return null;
-        }
-
         Context ctx = getContext();
         UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
         Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
@@ -804,7 +796,7 @@
                 case 26:
                     // QSB was moved to the grid. Clear the first row on screen 0.
                     if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
-                            !LauncherDbUtils.prepareScreenZeroToHostQsb(db)) {
+                            !LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
                         break;
                     }
                 case 27: {
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 19cc0fb..39c466d 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -23,14 +23,10 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.res.Resources;
-import android.os.Build;
 import android.util.Log;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
 
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsTransitionController;
@@ -229,7 +225,6 @@
             final boolean animated, int animType, final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
-        final boolean material = Utilities.ATLEAST_LOLLIPOP;
         final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
         final int revealDurationSlide = res.getInteger(R.integer.config_overlaySlideRevealTime);
 
@@ -276,20 +271,11 @@
             revealView.setTranslationX(0f);
 
             // Calculate the final animation values
-            final float revealViewToAlpha;
-            final float revealViewToXDrift;
-            final float revealViewToYDrift;
-            if (material) {
-                int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(
-                        revealView, buttonView, null);
-                revealViewToAlpha = pCb.materialRevealViewFinalAlpha;
-                revealViewToYDrift = buttonViewToPanelDelta[1];
-                revealViewToXDrift = buttonViewToPanelDelta[0];
-            } else {
-                revealViewToAlpha = 0f;
-                revealViewToYDrift = 2 * height / 3;
-                revealViewToXDrift = 0;
-            }
+            int[] buttonViewToPanelDelta =
+                    Utilities.getCenterDeltaInScreenSpace(revealView, buttonView);
+            final float revealViewToAlpha = pCb.materialRevealViewFinalAlpha;
+            final float revealViewToXDrift = buttonViewToPanelDelta[0];
+            final float revealViewToYDrift = buttonViewToPanelDelta[1];
 
             // Create the animators
             PropertyValuesHolder panelAlpha =
@@ -327,19 +313,17 @@
             itemsAlpha.setStartDelay(itemsAlphaStagger);
             animation.play(itemsAlpha);
 
-            if (material) {
-                float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
-                AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
-                        revealView, buttonView);
-                Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
-                        startRadius, revealRadius).createRevealAnimator(revealView);
-                reveal.setDuration(revealDuration);
-                reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-                if (listener != null) {
-                    reveal.addListener(listener);
-                }
-                animation.play(reveal);
+            float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
+            AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
+                    revealView, buttonView);
+            Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+                    startRadius, revealRadius).createRevealAnimator(revealView);
+            reveal.setDuration(revealDuration);
+            reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+            if (listener != null) {
+                reveal.addListener(listener);
             }
+            animation.play(reveal);
 
             animation.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -531,11 +515,9 @@
             final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
-        final boolean material = Utilities.ATLEAST_LOLLIPOP;
         final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
         final int revealDurationSlide = res.getInteger(R.integer.config_overlaySlideRevealTime);
-        final int itemsAlphaStagger =
-                res.getInteger(R.integer.config_overlayItemsAlphaStagger);
+        final int itemsAlphaStagger = res.getInteger(R.integer.config_overlayItemsAlphaStagger);
 
         final View toView = mLauncher.getWorkspace();
         final View revealView = fromView.getRevealView();
@@ -579,24 +561,14 @@
                 layerViews.addView(revealView);
 
                 // Calculate the final animation values
-                final float revealViewToXDrift;
-                final float revealViewToYDrift;
-                if (material) {
-                    int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
-                            buttonView, null);
-                    revealViewToYDrift = buttonViewToPanelDelta[1];
-                    revealViewToXDrift = buttonViewToPanelDelta[0];
-                } else {
-                    revealViewToYDrift = 2 * height / 3;
-                    revealViewToXDrift = 0;
-                }
+                int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView, buttonView);
+                final float revealViewToXDrift = buttonViewToPanelDelta[0];
+                final float revealViewToYDrift = buttonViewToPanelDelta[1];
 
                 // The vertical motion of the apps panel should be delayed by one frame
                 // from the conceal animation in order to give the right feel. We correspondingly
                 // shorten the duration so that the slide and conceal end at the same time.
-                TimeInterpolator decelerateInterpolator = material ?
-                        new LogDecelerateInterpolator(100, 0) :
-                        new DecelerateInterpolator(1f);
+                TimeInterpolator decelerateInterpolator = new LogDecelerateInterpolator(100, 0);
                 ObjectAnimator panelDriftY = ObjectAnimator.ofFloat(revealView, "translationY",
                         0, revealViewToYDrift);
                 panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
@@ -612,13 +584,10 @@
                 animation.play(panelDriftX);
 
                 // Setup animation for the reveal panel alpha
-                final float revealViewToAlpha = !material ? 0f :
-                        pCb.materialRevealViewFinalAlpha;
-                if (revealViewToAlpha != 1f) {
+                if (pCb.materialRevealViewFinalAlpha != 1f) {
                     ObjectAnimator panelAlpha = ObjectAnimator.ofFloat(revealView, "alpha",
-                            1f, revealViewToAlpha);
-                    panelAlpha.setDuration(material ? revealDuration : 150);
-                    panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                            1f, pCb.materialRevealViewFinalAlpha);
+                    panelAlpha.setDuration(revealDuration);
                     panelAlpha.setInterpolator(decelerateInterpolator);
                     animation.play(panelAlpha);
                 }
@@ -652,21 +621,19 @@
                 });
                 animation.play(invalidateScrim);
 
-                if (material) {
-                    // Animate the all apps button
-                    float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
-                    AnimatorListenerAdapter listener =
-                            pCb.getMaterialRevealViewAnimatorListener(revealView, buttonView);
-                    Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
-                            revealRadius, finalRadius).createRevealAnimator(revealView);
-                    reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-                    reveal.setDuration(revealDuration);
-                    reveal.setStartDelay(itemsAlphaStagger);
-                    if (listener != null) {
-                        reveal.addListener(listener);
-                    }
-                    animation.play(reveal);
+                // Animate the all apps button
+                float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
+                AnimatorListenerAdapter listener =
+                        pCb.getMaterialRevealViewAnimatorListener(revealView, buttonView);
+                Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+                        revealRadius, finalRadius).createRevealAnimator(revealView);
+                reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+                reveal.setDuration(revealDuration);
+                reveal.setStartDelay(itemsAlphaStagger);
+                if (listener != null) {
+                    reveal.addListener(listener);
                 }
+                animation.play(reveal);
             }
 
             animation.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ee7f9f8..76e2073 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -22,13 +22,11 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -565,7 +563,7 @@
     protected boolean computeScrollHelper(boolean shouldInvalidate) {
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
-            if (getScrollX() != mScroller.getCurrX()
+            if (getUnboundedScrollX() != mScroller.getCurrX()
                     || getScrollY() != mScroller.getCurrY()) {
                 float scaleX = mFreeScroll ? getScaleX() : 1f;
                 int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX));
@@ -1372,8 +1370,12 @@
         dampedOverScroll(amount);
     }
 
-    public void enableFreeScroll() {
+    /**
+     * return true if freescroll has been enabled, false otherwise
+     */
+    public boolean enableFreeScroll() {
         setEnableFreeScroll(true);
+        return true;
     }
 
     public void disableFreeScroll() {
@@ -1943,6 +1945,7 @@
         // Trigger a compute() to finish switching pages if necessary
         if (immediate) {
             computeScroll();
+            pageEndTransition();
         }
 
         invalidate();
@@ -2074,20 +2077,14 @@
         if (!mReorderingStarted) return;
         mReorderingStarted = false;
 
-        // If we haven't flung-to-delete the current child, then we just animate the drag view
-        // back into position
-        final Runnable onCompleteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                onEndReordering();
-            }
-        };
-
         mPostReorderingPreZoomInRunnable = new Runnable() {
             public void run() {
-                onCompleteRunnable.run();
+                // If we haven't flung-to-delete the current child,
+                // then we just animate the drag view back into position
+                onEndReordering();
+
                 enableFreeScroll();
-            };
+            }
         };
 
         mPostReorderingPreZoomInRemainingAnimationCount =
@@ -2100,7 +2097,6 @@
 
     /* Accessibility */
     @SuppressWarnings("deprecation")
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
@@ -2117,9 +2113,7 @@
         // Besides disabling the accessibility long-click, this also prevents this view from getting
         // accessibility focus.
         info.setLongClickable(false);
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
-        }
+        info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
     }
 
     @Override
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index 7c92f80..2976807 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources.Theme;
@@ -26,7 +25,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Bundle;
 import android.text.Layout;
 import android.text.StaticLayout;
@@ -63,7 +61,6 @@
     private final TextPaint mPaint;
     private Layout mSetupTextLayout;
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
             IconCache cache, boolean disabledForSafeMode) {
         super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
@@ -81,10 +78,7 @@
         setBackgroundResource(R.drawable.quantum_panel_dark);
         setWillNotDraw(false);
 
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
-        }
-
+        setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
         updateIcon(cache);
         updateAppWidget(null);
         setOnClickListener(mLauncher);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index eebce45..f8742f8 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -18,7 +18,6 @@
 
 import android.app.WallpaperManager;
 import android.content.Context;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewGroup;
@@ -148,17 +147,16 @@
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
 
                 if (child instanceof LauncherAppWidgetHostView) {
+                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
+
                     // Scale and center the widget to fit within its cells.
                     DeviceProfile profile = mLauncher.getDeviceProfile();
                     float scaleX = profile.appWidgetScale.x;
                     float scaleY = profile.appWidgetScale.y;
 
-                    float scale = Math.min(scaleX, scaleY);
-                    child.setScaleX(scale);
-                    child.setScaleY(scale);
-
-                    child.setTranslationX(-(lp.width - (lp.width * scaleX)) / 2.0f);
-                    child.setTranslationY(-(lp.height - (lp.height * scaleY)) / 2.0f);
+                    lahv.setScaleToFit(Math.min(scaleX, scaleY));
+                    lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
+                            -(lp.height - (lp.height * scaleY)) / 2.0f);
                 }
 
                 int childLeft = lp.x;
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index b9010c7..05fb1ed 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -17,7 +17,6 @@
 package com.android.launcher3;
 
 import android.annotation.TargetApi;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -37,7 +36,7 @@
 /**
  * Represents a launchable icon on the workspaces and in folders.
  */
-public class ShortcutInfo extends ItemInfo {
+public class ShortcutInfo extends ItemInfoWithIcon {
 
     public static final int DEFAULT = 0;
 
@@ -77,22 +76,12 @@
     public Intent intent;
 
     /**
-     * Indicates whether we're using a low res icon
-     */
-    public boolean usingLowResIcon;
-
-    /**
      * If isShortcut=true and customIcon=false, this contains a reference to the
      * shortcut icon as an application's resource.
      */
     public Intent.ShortcutIconResource iconResource;
 
     /**
-     * The application icon.
-     */
-    public Bitmap iconBitmap;
-
-    /**
      * Indicates that the icon is disabled due to safe mode restrictions.
      */
     public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
@@ -152,16 +141,6 @@
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
 
-    @Override
-    public Intent getIntent() {
-        return intent;
-    }
-
-    /** Returns {@link #promisedIntent}, or {@link #intent} if promisedIntent is null. */
-    public Intent getPromisedIntent() {
-        return promisedIntent != null ? promisedIntent : intent;
-    }
-
     public ShortcutInfo(ShortcutInfo info) {
         super(info);
         title = info.title;
@@ -197,7 +176,7 @@
     void onAddToDatabase(ContentWriter writer) {
         super.onAddToDatabase(writer);
         writer.put(LauncherSettings.BaseLauncherColumns.TITLE, title)
-                .put(LauncherSettings.BaseLauncherColumns.INTENT, getPromisedIntent())
+                .put(LauncherSettings.BaseLauncherColumns.INTENT, getIntent())
                 .put(LauncherSettings.Favorites.RESTORED, status);
 
         if (!usingLowResIcon) {
@@ -210,8 +189,12 @@
         }
     }
 
-    public ComponentName getTargetComponent() {
-        return getPromisedIntent().getComponent();
+    /**
+     *  Returns {@link #promisedIntent}, or {@link #intent} if promisedIntent is null.
+     */
+    @Override
+    public Intent getIntent() {
+        return promisedIntent != null ? promisedIntent : intent;
     }
 
     public boolean hasStatusFlag(int flag) {
@@ -270,19 +253,14 @@
         AppInfo appInfo = new AppInfo();
         appInfo.user = user;
         appInfo.componentName = shortcutInfo.getActivity();
-        try {
-            cache.getTitleAndIcon(appInfo, shortcutInfo.getActivityInfo(context), false);
-        } catch (NullPointerException e) {
-            // This may happen when we fail to load the activity info. Worst case ignore badging.
-            return LauncherIcons.badgeIconForUser(unbadgedBitmap, user, context);
-        }
+        cache.getTitleAndIcon(appInfo, false);
         return LauncherIcons.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
     }
 
     /** Returns the ShortcutInfo id associated with the deep shortcut. */
     public String getDeepShortcutId() {
         return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT ?
-                getPromisedIntent().getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
+                getIntent().getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
     }
 
     @Override
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index a7839ec..73a9f64 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -1,12 +1,10 @@
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -40,15 +38,12 @@
         return supportsDrop(getContext(), info);
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     public static boolean supportsDrop(Context context, Object info) {
-        if (Utilities.ATLEAST_JB_MR2) {
-            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-            Bundle restrictions = userManager.getUserRestrictions();
-            if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
-                    || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
-                return false;
-            }
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        Bundle restrictions = userManager.getUserRestrictions();
+        if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
+                || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
+            return false;
         }
 
         return getUninstallTarget(context, info) != null;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 6485fc1..2cb9138 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.WallpaperManager;
 import android.content.ActivityNotFoundException;
@@ -105,18 +104,6 @@
     public static final boolean ATLEAST_LOLLIPOP_MR1 =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
 
-    public static final boolean ATLEAST_LOLLIPOP =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
-
-    public static final boolean ATLEAST_KITKAT =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
-    public static final boolean ATLEAST_JB_MR1 =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
-
-    public static final boolean ATLEAST_JB_MR2 =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
-
     // An intent extra to indicate the horizontal scroll of the wallpaper.
     public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
 
@@ -229,7 +216,7 @@
                 localY < (v.getHeight() + slop);
     }
 
-    public static int[] getCenterDeltaInScreenSpace(View v0, View v1, int[] delta) {
+    public static int[] getCenterDeltaInScreenSpace(View v0, View v1) {
         v0.getLocationInWindow(sLoc0);
         v1.getLocationInWindow(sLoc1);
 
@@ -237,15 +224,7 @@
         sLoc0[1] += (v0.getMeasuredHeight() * v0.getScaleY()) / 2;
         sLoc1[0] += (v1.getMeasuredWidth() * v1.getScaleX()) / 2;
         sLoc1[1] += (v1.getMeasuredHeight() * v1.getScaleY()) / 2;
-
-        if (delta == null) {
-            delta = new int[2];
-        }
-
-        delta[0] = sLoc1[0] - sLoc0[0];
-        delta[1] = sLoc1[1] - sLoc0[1];
-
-        return delta;
+        return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]};
     }
 
     public static void scaleRectAboutCenter(Rect r, float scale) {
@@ -479,10 +458,8 @@
         System.out.println(b.toString());
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public static boolean isRtl(Resources res) {
-        return ATLEAST_JB_MR1 &&
-                (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
+        return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
     }
 
     /**
@@ -569,16 +546,11 @@
      * @param msg original message
      * @param ttsMsg message to be spoken
      */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static CharSequence wrapForTts(CharSequence msg, String ttsMsg) {
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            SpannableString spanned = new SpannableString(msg);
-            spanned.setSpan(new TtsSpan.TextBuilder(ttsMsg).build(),
-                    0, spanned.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-            return spanned;
-        } else {
-            return msg;
-        }
+        SpannableString spanned = new SpannableString(msg);
+        spanned.setSpan(new TtsSpan.TextBuilder(ttsMsg).build(),
+                0, spanned.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+        return spanned;
     }
 
     /**
@@ -593,10 +565,9 @@
                 LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE);
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static boolean isPowerSaverOn(Context context) {
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        return ATLEAST_LOLLIPOP && powerManager.isPowerSaveMode();
+        return powerManager.isPowerSaveMode();
     }
 
     public static boolean isWallpaperAllowed(Context context) {
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 399920e..0f62b31 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -302,7 +302,7 @@
         Drawable drawable = null;
         if (info.previewImage != 0) {
             try {
-                drawable = mWidgetManager.loadPreview(info);
+                drawable = info.loadPreviewImage(launcher.getApplicationContext(), 0);
             } catch (OutOfMemoryError e) {
                 Log.w(TAG, "Error loading widget preview for: " + info.provider, e);
                 // During OutOfMemoryError, the previous heap stack is not affected. Catching
@@ -395,7 +395,7 @@
             float iconScale = Math.min((float) smallestSide / (appIconSize + 2 * minOffset), scale);
 
             try {
-                Drawable icon = mWidgetManager.loadIcon(info, mIconCache);
+                Drawable icon = info.getIcon(launcher, mIconCache);
                 if (icon != null) {
                     icon = mutateOnMainThread(icon);
                     int hoffset = (int) ((tileW - appIconSize * iconScale) / 2) + x;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 43a1a22..cf6b025 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1386,12 +1386,10 @@
         // it's own settling, and every gesture to the overlay should be self-contained and start
         // from 0, so we zero it out here.
         if (isScrollingOverlay()) {
-            int finalScroll = mIsRtl ? mMaxScrollX : 0;
-
             // We reset mWasInOverscroll so that PagedView doesn't zero out the overscroll
-            // interaction when we call scrollTo.
+            // interaction when we call snapToPageImmediately.
             mWasInOverscroll = false;
-            scrollTo(finalScroll, getScrollY());
+            snapToPageImmediately(0);
         } else {
             super.snapToDestination();
         }
@@ -1781,11 +1779,6 @@
     }
 
     protected void onResume() {
-        // Update wallpaper dimensions if they were changed since last onResume
-        // (we also always set the wallpaper dimensions in the constructor)
-        if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {
-            setWallpaperDimension();
-        }
         mWallpaperOffset.onResume();
     }
 
@@ -2090,20 +2083,13 @@
     public void updateAccessibilityFlags() {
         // TODO: Update the accessibility flags appropriately when dragging.
         if (!mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
-            if (Utilities.ATLEAST_LOLLIPOP) {
-                int total = getPageCount();
-                for (int i = numCustomPages(); i < total; i++) {
-                    updateAccessibilityFlags((CellLayout) getPageAt(i), i);
-                }
-                setImportantForAccessibility((mState == State.NORMAL || mState == State.OVERVIEW)
-                        ? IMPORTANT_FOR_ACCESSIBILITY_AUTO
-                        : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-            } else {
-                int accessible = mState == State.NORMAL ?
-                        IMPORTANT_FOR_ACCESSIBILITY_AUTO :
-                        IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
-                setImportantForAccessibility(accessible);
+            int total = getPageCount();
+            for (int i = numCustomPages(); i < total; i++) {
+                updateAccessibilityFlags((CellLayout) getPageAt(i), i);
             }
+            setImportantForAccessibility((mState == State.NORMAL || mState == State.OVERVIEW)
+                    ? IMPORTANT_FOR_ACCESSIBILITY_AUTO
+                    : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
         }
     }
 
@@ -4115,6 +4101,16 @@
         }
     }
 
+    @Override
+    public boolean enableFreeScroll() {
+        if (getState() == State.OVERVIEW) {
+            return super.enableFreeScroll();
+        } else {
+            Log.w(TAG, "enableFreeScroll called but not in overview: state=" + getState());
+            return false;
+        }
+    }
+
     /**
      * Used as a workaround to ensure that the AppWidgetService receives the
      * PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 83391f3..9347852 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -1,11 +1,9 @@
 package com.android.launcher3.accessibility;
 
-import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.DialogInterface;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.text.TextUtils;
@@ -21,10 +19,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.folder.Folder;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.InfoDropTarget;
 import com.android.launcher3.ItemInfo;
@@ -39,13 +34,13 @@
 import com.android.launcher3.UninstallDropTarget;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragController.DragListener;
-import com.android.launcher3.shortcuts.DeepShortcutTextView;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.folder.Folder;
 import com.android.launcher3.shortcuts.DeepShortcutsContainer;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LauncherAccessibilityDelegate extends AccessibilityDelegate implements DragListener {
 
     private static final String TAG = "LauncherAccessibilityDelegate";
@@ -120,7 +115,7 @@
         if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
             info.addAction(mActions.get(UNINSTALL));
         }
-        if (InfoDropTarget.supportsDrop(item)) {
+        if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
             info.addAction(mActions.get(INFO));
         }
 
diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
index 5f68f90..edb0b16 100644
--- a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
@@ -16,21 +16,19 @@
 
 package com.android.launcher3.accessibility;
 
-import android.annotation.TargetApi;
 import android.content.Context;
-import android.os.Build;
 import android.os.Bundle;
 import android.util.SparseArray;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate {
 
     private static final int MOVE_BACKWARD = R.id.action_move_screen_backwards;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 97e0d98..a2266fe 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -261,9 +261,7 @@
                 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
         mSearchInput.setHint(spanned);
 
-        mElevationController = Utilities.ATLEAST_LOLLIPOP
-                ? new HeaderElevationController.ControllerVL(mSearchContainer)
-                : new HeaderElevationController.ControllerV16(mSearchContainer);
+        mElevationController = new HeaderElevationController(mSearchContainer);
 
         // Load the all apps recycler view
         mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
diff --git a/src/com/android/launcher3/allapps/HeaderElevationController.java b/src/com/android/launcher3/allapps/HeaderElevationController.java
index e79e5c7..b167fed 100644
--- a/src/com/android/launcher3/allapps/HeaderElevationController.java
+++ b/src/com/android/launcher3/allapps/HeaderElevationController.java
@@ -1,16 +1,10 @@
 package com.android.launcher3.allapps;
 
-import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.GradientDrawable;
-import android.os.Build;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
-import android.widget.FrameLayout;
 
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.R;
@@ -19,10 +13,40 @@
 /**
  * Helper class for controlling the header elevation in response to RecyclerView scroll.
  */
-public abstract class HeaderElevationController extends RecyclerView.OnScrollListener {
+public class HeaderElevationController extends RecyclerView.OnScrollListener {
+
+    private final View mHeader;
+    private final float mMaxElevation;
+    private final float mScrollToElevation;
 
     private int mCurrentY = 0;
 
+    public HeaderElevationController(View header) {
+        mHeader = header;
+        final Resources res = mHeader.getContext().getResources();
+        mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
+        mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
+
+        // We need to provide a custom outline so the shadow only appears on the bottom edge.
+        // The top, left and right edges are all extended out, and the shadow is clipped
+        // by the parent.
+        final ViewOutlineProvider vop = new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                final View parent = (View) mHeader.getParent();
+
+                final int left = parent.getLeft(); // Use the parent to account for offsets
+                final int top = view.getTop();
+                final int right = left + view.getWidth();
+                final int bottom = view.getBottom();
+
+                final int offset = Utilities.pxFromDp(mMaxElevation, res.getDisplayMetrics());
+                outline.setRect(left - offset, top - offset, right + offset, bottom);
+            }
+        };
+        mHeader.setOutlineProvider(vop);
+    }
+
     public void reset() {
         mCurrentY = 0;
         onScroll(mCurrentY);
@@ -34,88 +58,12 @@
         onScroll(mCurrentY);
     }
 
-    public void updateBackgroundPadding(Rect bgPadding) { }
-
-    abstract void onScroll(int scrollY);
-
-    public static class ControllerV16 extends HeaderElevationController {
-
-        private final View mShadow;
-        private final float mScrollToElevation;
-
-        public ControllerV16(View header) {
-            Resources res = header.getContext().getResources();
-            mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
-
-            mShadow = new View(header.getContext());
-            mShadow.setBackground(new GradientDrawable(
-                    GradientDrawable.Orientation.TOP_BOTTOM, new int[] {0x1E000000, 0x00000000}));
-            mShadow.setAlpha(0);
-
-            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
-                    FrameLayout.LayoutParams.MATCH_PARENT,
-                    res.getDimensionPixelSize(R.dimen.all_apps_header_shadow_height));
-            lp.topMargin = ((FrameLayout.LayoutParams) header.getLayoutParams()).height;
-
-            ((ViewGroup) header.getParent()).addView(mShadow, lp);
-        }
-
-        @Override
-        public void onScroll(int scrollY) {
-            float elevationPct = (float) Math.min(scrollY, mScrollToElevation) /
-                    mScrollToElevation;
-            mShadow.setAlpha(elevationPct);
-        }
-
-        @Override
-        public void updateBackgroundPadding(Rect bgPadding) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mShadow.getLayoutParams();
-            lp.leftMargin = bgPadding.left;
-            lp.rightMargin = bgPadding.right;
-            mShadow.requestLayout();
+    private void onScroll(int scrollY) {
+        float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
+        float newElevation = mMaxElevation * elevationPct;
+        if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
+            mHeader.setElevation(newElevation);
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public static class ControllerVL extends HeaderElevationController {
-
-        private final View mHeader;
-        private final float mMaxElevation;
-        private final float mScrollToElevation;
-
-        public ControllerVL(View header) {
-            mHeader = header;
-            final Resources res = mHeader.getContext().getResources();
-            mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
-            mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
-
-            // We need to provide a custom outline so the shadow only appears on the bottom edge.
-            // The top, left and right edges are all extended out, and the shadow is clipped
-            // by the parent.
-            final ViewOutlineProvider vop = new ViewOutlineProvider() {
-                @Override
-                public void getOutline(View view, Outline outline) {
-                    final View parent = (View) mHeader.getParent();
-
-                    final int left = parent.getLeft(); // Use the parent to account for offsets
-                    final int top = view.getTop();
-                    final int right = left + view.getWidth();
-                    final int bottom = view.getBottom();
-
-                    final int offset = Utilities.pxFromDp(mMaxElevation, res.getDisplayMetrics());
-                    outline.setRect(left - offset, top - offset, right + offset, bottom);
-                }
-            };
-            mHeader.setOutlineProvider(vop);
-        }
-
-        @Override
-        public void onScroll(int scrollY) {
-            float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
-            float newElevation = mMaxElevation * elevationPct;
-            if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
-                mHeader.setElevation(newElevation);
-            }
-        }
-    }
 }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 5388f2a..af43c02 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -23,13 +23,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.UserHandle;
 
-import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.ComponentKey;
 
 import java.util.HashMap;
@@ -40,15 +37,10 @@
     private static final Object sInstanceLock = new Object();
     private static AppWidgetManagerCompat sInstance;
 
-
     public static AppWidgetManagerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.ATLEAST_LOLLIPOP) {
-                    sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext());
-                } else {
-                    sInstance = new AppWidgetManagerCompatV16(context.getApplicationContext());
-                }
+                sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext());
             }
             return sInstance;
         }
@@ -73,20 +65,12 @@
 
     public abstract List<AppWidgetProviderInfo> getAllProviders();
 
-    public abstract String loadLabel(LauncherAppWidgetProviderInfo info);
-
     public abstract boolean bindAppWidgetIdIfAllowed(
             int appWidgetId, AppWidgetProviderInfo info, Bundle options);
 
-    public abstract UserHandle getUser(LauncherAppWidgetProviderInfo info);
-
     public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
             Activity activity, AppWidgetHost host, int requestCode);
 
-    public abstract Drawable loadPreview(AppWidgetProviderInfo info);
-
-    public abstract Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache);
-
     public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
             int imageWidth, int imageHeight);
 
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
deleted file mode 100644
index e7d8e29..0000000
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.UserHandle;
-
-import com.android.launcher3.IconCache;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.ComponentKey;
-
-import java.util.HashMap;
-import java.util.List;
-
-class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat {
-
-    AppWidgetManagerCompatV16(Context context) {
-        super(context);
-    }
-
-    @Override
-    public List<AppWidgetProviderInfo> getAllProviders() {
-        return mAppWidgetManager.getInstalledProviders();
-    }
-
-    @Override
-    public String loadLabel(LauncherAppWidgetProviderInfo info) {
-        return Utilities.trim(info.label);
-    }
-
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    @Override
-    public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
-            Bundle options) {
-        if (Utilities.ATLEAST_JB_MR1) {
-            return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider, options);
-        } else {
-            return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider);
-        }
-    }
-
-    @Override
-    public UserHandle getUser(LauncherAppWidgetProviderInfo info) {
-        return Process.myUserHandle();
-    }
-
-    @Override
-    public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
-            AppWidgetHost host, int requestCode) {
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
-        intent.setComponent(info.configure);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
-        Utilities.startActivityForResultSafely(activity, intent, requestCode);
-    }
-
-    @Override
-    public Drawable loadPreview(AppWidgetProviderInfo info) {
-        return mContext.getPackageManager().getDrawable(
-                info.provider.getPackageName(), info.previewImage, null);
-    }
-
-    @Override
-    public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) {
-        return cache.getFullResIcon(info.provider.getPackageName(), info.icon);
-    }
-
-    @Override
-    public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
-            int imageWidth, int imageHeight) {
-        return bitmap;
-    }
-
-    @Override
-    public LauncherAppWidgetProviderInfo findProvider(
-            ComponentName provider, UserHandle user) {
-        for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) {
-            if (info.provider.equals(provider)) {
-                return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() {
-        HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>();
-        UserHandle user = Process.myUserHandle();
-        for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) {
-            result.put(new ComponentKey(info.provider, user), info);
-        }
-        return result;
-    }
-}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 0acf753..56a7f46 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.compat;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetProviderInfo;
@@ -31,15 +30,12 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.view.View;
 import android.widget.Toast;
 
-import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.util.ComponentKey;
@@ -48,7 +44,6 @@
 import java.util.HashMap;
 import java.util.List;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
 
     private final UserManager mUserManager;
@@ -70,11 +65,6 @@
     }
 
     @Override
-    public String loadLabel(LauncherAppWidgetProviderInfo info) {
-        return info.getLabel(mPm);
-    }
-
-    @Override
     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
             Bundle options) {
         return mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -82,14 +72,6 @@
     }
 
     @Override
-    public UserHandle getUser(LauncherAppWidgetProviderInfo info) {
-        if (info.isCustomWidget) {
-            return Process.myUserHandle();
-        }
-        return info.getProfile();
-    }
-
-    @Override
     public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
             AppWidgetHost host, int requestCode) {
         try {
@@ -100,16 +82,6 @@
     }
 
     @Override
-    public Drawable loadPreview(AppWidgetProviderInfo info) {
-        return info.loadPreviewImage(mContext, 0);
-    }
-
-    @Override
-    public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) {
-        return info.getIcon(mContext, cache);
-    }
-
-    @Override
     public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
             int imageWidth, int imageHeight) {
         if (info.isCustomWidget || info.getProfile().equals(android.os.Process.myUserHandle())) {
diff --git a/src/com/android/launcher3/compat/DeferredLauncherActivityInfo.java b/src/com/android/launcher3/compat/DeferredLauncherActivityInfo.java
deleted file mode 100644
index 4dd05bb..0000000
--- a/src/com/android/launcher3/compat/DeferredLauncherActivityInfo.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.compat;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-
-/**
- * {@link LauncherActivityInfoCompat} which loads its data only when needed.
- */
-public class DeferredLauncherActivityInfo extends LauncherActivityInfoCompat {
-
-    private final ComponentName mComponent;
-    private final UserHandle mUser;
-    private final Context mContext;
-
-    private LauncherActivityInfoCompat mActualInfo;
-
-    public DeferredLauncherActivityInfo(
-            ComponentName component, UserHandle user, Context context) {
-        mComponent = component;
-        mUser = user;
-        mContext = context;
-    }
-
-    @Override
-    public ComponentName getComponentName() {
-        return mComponent;
-    }
-
-    @Override
-    public UserHandle getUser() {
-        return mUser;
-    }
-
-    private synchronized LauncherActivityInfoCompat getActualInfo() {
-        if (mActualInfo == null) {
-            Intent intent = new Intent(Intent.ACTION_MAIN)
-                    .addCategory(Intent.CATEGORY_LAUNCHER)
-                    .setComponent(mComponent);
-            mActualInfo = LauncherAppsCompat.getInstance(mContext).resolveActivity(intent, mUser);
-        }
-        return mActualInfo;
-    }
-
-    @Override
-    public CharSequence getLabel() {
-        return getActualInfo().getLabel();
-    }
-
-    @Override
-    public Drawable getIcon(int density) {
-        return getActualInfo().getIcon(density);
-    }
-
-    @Override
-    public ApplicationInfo getApplicationInfo() {
-        return getActualInfo().getApplicationInfo();
-    }
-
-    @Override
-    public long getFirstInstallTime() {
-        return getActualInfo().getFirstInstallTime();
-    }
-}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
deleted file mode 100644
index d697803..0000000
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Process;
-import android.os.UserHandle;
-
-
-public class LauncherActivityInfoCompatV16 extends LauncherActivityInfoCompat {
-    private final ResolveInfo mResolveInfo;
-    private final ActivityInfo mActivityInfo;
-    private final ComponentName mComponentName;
-    private final PackageManager mPm;
-
-    LauncherActivityInfoCompatV16(Context context, ResolveInfo info) {
-        super();
-        mResolveInfo = info;
-        mActivityInfo = info.activityInfo;
-        mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
-        mPm = context.getPackageManager();
-    }
-
-    public ComponentName getComponentName() {
-        return mComponentName;
-    }
-
-    public UserHandle getUser() {
-        return Process.myUserHandle();
-    }
-
-    public CharSequence getLabel() {
-        return mResolveInfo.loadLabel(mPm);
-    }
-
-    public Drawable getIcon(int density) {
-        int iconRes = mResolveInfo.getIconResource();
-        Resources resources = null;
-        Drawable icon = null;
-        // Get the preferred density icon from the app's resources
-        if (density != 0 && iconRes != 0) {
-            try {
-                resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
-                icon = resources.getDrawableForDensity(iconRes, density);
-            } catch (NameNotFoundException | Resources.NotFoundException exc) {
-            }
-        }
-        // Get the default density icon
-        if (icon == null) {
-            icon = mResolveInfo.loadIcon(mPm);
-        }
-        if (icon == null) {
-            resources = Resources.getSystem();
-            icon = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
-        }
-        return icon;
-    }
-
-    public ApplicationInfo getApplicationInfo() {
-        return mActivityInfo.applicationInfo;
-    }
-
-    public long getFirstInstallTime() {
-        try {
-            PackageInfo info = mPm.getPackageInfo(mActivityInfo.packageName, 0);
-            return info != null ? info.firstInstallTime : 0;
-        } catch (NameNotFoundException e) {
-            return 0;
-        }
-    }
-
-    public String getName() {
-        return mActivityInfo.name;
-    }
-}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
index 874b3c3..c3b9592 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
@@ -16,15 +16,12 @@
 
 package com.android.launcher3.compat;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.UserHandle;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat {
     private LauncherActivityInfo mLauncherActivityInfo;
 
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index c75298b..73ab36c 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -23,7 +23,6 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 
 import java.util.List;
@@ -51,11 +50,7 @@
     public static LauncherAppsCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.ATLEAST_LOLLIPOP) {
-                    sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
-                } else {
-                    sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
-                }
+                sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
             }
             return sInstance;
         }
@@ -73,5 +68,4 @@
     public abstract boolean isPackageEnabledForProfile(String packageName, UserHandle user);
     public abstract boolean isActivityEnabledForProfile(ComponentName component,
             UserHandle user);
-    public abstract boolean isPackageSuspendedForProfile(String packageName, UserHandle user);
 }
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
deleted file mode 100644
index 0d1efa8..0000000
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.Thunk;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Version of {@link LauncherAppsCompat} for devices with API level 16.
- * Devices Pre-L don't support multiple profiles in one launcher so
- * user parameters are ignored and all methods operate on the current user.
- */
-public class LauncherAppsCompatV16 extends LauncherAppsCompat {
-
-    private PackageManager mPm;
-    private Context mContext;
-    private List<OnAppsChangedCallbackCompat> mCallbacks
-            = new ArrayList<OnAppsChangedCallbackCompat>();
-    private PackageMonitor mPackageMonitor;
-
-    LauncherAppsCompatV16(Context context) {
-        mPm = context.getPackageManager();
-        mContext = context;
-        mPackageMonitor = new PackageMonitor();
-   }
-
-    public List<LauncherActivityInfoCompat> getActivityList(String packageName,
-            UserHandle user) {
-        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
-        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-        mainIntent.setPackage(packageName);
-        List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
-        List<LauncherActivityInfoCompat> list =
-                new ArrayList<LauncherActivityInfoCompat>(infos.size());
-        for (ResolveInfo info : infos) {
-            list.add(new LauncherActivityInfoCompatV16(mContext, info));
-        }
-        return list;
-    }
-
-    public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandle user) {
-        ResolveInfo info = mPm.resolveActivity(intent, 0);
-        if (info != null) {
-            return new LauncherActivityInfoCompatV16(mContext, info);
-        }
-        return null;
-    }
-
-    public void startActivityForProfile(ComponentName component, UserHandle user,
-            Rect sourceBounds, Bundle opts) {
-        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
-        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-        launchIntent.setComponent(component);
-        launchIntent.setSourceBounds(sourceBounds);
-        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(launchIntent, opts);
-    }
-
-    public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
-        String packageName = component.getPackageName();
-        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
-                Uri.fromParts("package", packageName, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
-                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        mContext.startActivity(intent, null);
-    }
-
-    public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
-        if (callback != null && !mCallbacks.contains(callback)) {
-            mCallbacks.add(callback);
-            if (mCallbacks.size() == 1) {
-                registerForPackageIntents();
-            }
-        }
-    }
-
-    public synchronized void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
-        mCallbacks.remove(callback);
-        if (mCallbacks.size() == 0) {
-            unregisterForPackageIntents();
-        }
-    }
-
-    public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
-        return PackageManagerHelper.isAppEnabled(mPm, packageName);
-    }
-
-    public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
-        try {
-            ActivityInfo info = mPm.getActivityInfo(component, 0);
-            return info != null && info.isEnabled();
-        } catch (NameNotFoundException e) {
-            return false;
-        }
-    }
-
-    public boolean isPackageSuspendedForProfile(String packageName, UserHandle user) {
-        return false;
-    }
-
-    private void unregisterForPackageIntents() {
-        mContext.unregisterReceiver(mPackageMonitor);
-    }
-
-    private void registerForPackageIntents() {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addDataScheme("package");
-        mContext.registerReceiver(mPackageMonitor, filter);
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mPackageMonitor, filter);
-    }
-
-    @Thunk synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
-        return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
-    }
-
-    @Thunk class PackageMonitor extends BroadcastReceiver {
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            final UserHandle user = Process.myUserHandle();
-
-            if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
-                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
-                    || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
-                final String packageName = intent.getData().getSchemeSpecificPart();
-                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-
-                if (packageName == null || packageName.length() == 0) {
-                    // they sent us a bad intent
-                    return;
-                }
-                if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
-                    for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                        callback.onPackageChanged(packageName, user);
-                    }
-                } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
-                    if (!replacing) {
-                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                            callback.onPackageRemoved(packageName, user);
-                        }
-                    }
-                    // else, we are replacing the package, so a PACKAGE_ADDED will be sent
-                    // later, we will update the package at this time
-                } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
-                    if (!replacing) {
-                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                            callback.onPackageAdded(packageName, user);
-                        }
-                    } else {
-                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                            callback.onPackageChanged(packageName, user);
-                        }
-                    }
-                }
-            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
-                // EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted
-                // when moving a package or mounting/un-mounting external storage. Assume that
-                // it is a replacing operation.
-                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
-                        !Utilities.ATLEAST_KITKAT);
-                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                    callback.onPackagesAvailable(packages, user, replacing);
-                }
-            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                // This intent is broadcasted when moving a package or mounting/un-mounting
-                // external storage.
-                // However on Kitkat this is also sent when a package is being updated, and
-                // contains an extra Intent.EXTRA_REPLACING=true for that case.
-                // Using false as default for Intent.EXTRA_REPLACING gives correct value on
-                // lower devices as the intent is not sent when the app is updating/replacing.
-                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
-                    callback.onPackagesUnavailable(packages, user, replacing);
-                }
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index f408da0..60f9fab 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.compat;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -24,7 +23,6 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 
@@ -36,32 +34,30 @@
 import java.util.List;
 import java.util.Map;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class LauncherAppsCompatVL extends LauncherAppsCompatV16 {
+public class LauncherAppsCompatVL extends LauncherAppsCompat {
 
     protected LauncherApps mLauncherApps;
 
-    private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks
-            = new HashMap<OnAppsChangedCallbackCompat, WrappedCallback>();
+    private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks = new HashMap<>();
 
     LauncherAppsCompatVL(Context context) {
-        super(context);
-        mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
+        mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
     }
 
+    @Override
     public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandle user) {
         List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName, user);
         if (list.size() == 0) {
             return Collections.emptyList();
         }
-        ArrayList<LauncherActivityInfoCompat> compatList =
-                new ArrayList<LauncherActivityInfoCompat>(list.size());
+        ArrayList<LauncherActivityInfoCompat> compatList = new ArrayList<>(list.size());
         for (LauncherActivityInfo info : list) {
             compatList.add(new LauncherActivityInfoCompatVL(info));
         }
         return compatList;
     }
 
+    @Override
     public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandle user) {
         LauncherActivityInfo activity = mLauncherApps.resolveActivity(intent, user);
         if (activity != null) {
@@ -71,15 +67,18 @@
         }
     }
 
+    @Override
     public void startActivityForProfile(ComponentName component, UserHandle user,
             Rect sourceBounds, Bundle opts) {
         mLauncherApps.startMainActivity(component, user, sourceBounds, opts);
     }
 
+    @Override
     public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
         mLauncherApps.startAppDetailsActivity(component, user, null, null);
     }
 
+    @Override
     public void addOnAppsChangedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
         WrappedCallback wrappedCallback = new WrappedCallback(callback);
         synchronized (mCallbacks) {
@@ -88,9 +87,9 @@
         mLauncherApps.registerCallback(wrappedCallback);
     }
 
-    public void removeOnAppsChangedCallback(
-            LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
-        WrappedCallback wrappedCallback = null;
+    @Override
+    public void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
+        final WrappedCallback wrappedCallback;
         synchronized (mCallbacks) {
             wrappedCallback = mCallbacks.remove(callback);
         }
@@ -99,18 +98,16 @@
         }
     }
 
+    @Override
     public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
         return mLauncherApps.isPackageEnabled(packageName, user);
     }
 
+    @Override
     public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
         return mLauncherApps.isActivityEnabled(component, user);
     }
 
-    public boolean isPackageSuspendedForProfile(String packageName, UserHandle user) {
-        return false;
-    }
-
     private static class WrappedCallback extends LauncherApps.Callback {
         private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
 
@@ -147,7 +144,6 @@
             mCallback.onPackagesUnsuspended(packageNames, user);
         }
 
-        @Override
         public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
                 UserHandle user) {
             List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcuts.size());
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index ec5014d..c7fe0ce 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 
-import com.android.launcher3.Utilities;
-
 import java.util.HashMap;
 
 public abstract class PackageInstallerCompat {
@@ -34,11 +32,7 @@
     public static PackageInstallerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.ATLEAST_LOLLIPOP) {
-                    sInstance = new PackageInstallerCompatVL(context);
-                } else {
-                    sInstance = new PackageInstallerCompatV16();
-                }
+                sInstance = new PackageInstallerCompatVL(context);
             }
             return sInstance;
         }
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
deleted file mode 100644
index 654e349..0000000
--- a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import java.util.HashMap;
-
-public class PackageInstallerCompatV16 extends PackageInstallerCompat {
-
-    PackageInstallerCompatV16() { }
-
-    @Override
-    public void onStop() { }
-
-    @Override
-    public HashMap<String, Integer> updateAndGetActiveSessionCache() {
-        return new HashMap<>();
-    }
-}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 192cb0c..953d93d 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -16,12 +16,10 @@
 
 package com.android.launcher3.compat;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionCallback;
 import android.content.pm.PackageInstaller.SessionInfo;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
@@ -34,7 +32,6 @@
 
 import java.util.HashMap;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class PackageInstallerCompatVL extends PackageInstallerCompat {
 
     @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 24c95b1..25808d2 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -39,12 +39,8 @@
                     sInstance = new UserManagerCompatVN(context.getApplicationContext());
                 } else if (Utilities.ATLEAST_MARSHMALLOW) {
                     sInstance = new UserManagerCompatVM(context.getApplicationContext());
-                } else if (Utilities.ATLEAST_LOLLIPOP) {
-                    sInstance = new UserManagerCompatVL(context.getApplicationContext());
-                } else if (Utilities.ATLEAST_JB_MR1) {
-                    sInstance = new UserManagerCompatV17(context.getApplicationContext());
                 } else {
-                    sInstance = new UserManagerCompatV16();
+                    sInstance = new UserManagerCompatVL(context.getApplicationContext());
                 }
             }
             return sInstance;
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java
deleted file mode 100644
index 60374aa..0000000
--- a/src/com/android/launcher3/compat/UserManagerCompatV16.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import android.os.Process;
-import android.os.UserHandle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class UserManagerCompatV16 extends UserManagerCompat {
-
-    UserManagerCompatV16() {
-    }
-
-    public List<UserHandle> getUserProfiles() {
-        List<UserHandle> profiles = new ArrayList<UserHandle>(1);
-        profiles.add(Process.myUserHandle());
-        return profiles;
-    }
-
-    public UserHandle getUserForSerialNumber(long serialNumber) {
-        return Process.myUserHandle();
-    }
-
-    public long getSerialNumberForUser(UserHandle user) {
-        return 0;
-    }
-
-    public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) {
-        return label;
-    }
-
-    @Override
-    public long getUserCreationTime(UserHandle user) {
-        return 0;
-    }
-
-    @Override
-    public void enableAndResetCache() {
-    }
-
-    @Override
-    public boolean isQuietModeEnabled(UserHandle user) {
-        return false;
-    }
-
-    @Override
-    public boolean isUserUnlocked(UserHandle user) {
-        return true;
-    }
-
-    @Override
-    public boolean isDemoUser() {
-        return false;
-    }
-}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java
deleted file mode 100644
index 08e8947..0000000
--- a/src/com/android/launcher3/compat/UserManagerCompatV17.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.launcher3.compat;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import com.android.launcher3.util.LongArrayMap;
-
-import java.util.HashMap;
-
-@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-public class UserManagerCompatV17 extends UserManagerCompatV16 {
-
-    protected LongArrayMap<UserHandle> mUsers;
-    // Create a separate reverse map as LongArrayMap.indexOfValue checks if objects are same
-    // and not {@link Object#equals}
-    protected HashMap<UserHandle, Long> mUserToSerialMap;
-
-    protected UserManager mUserManager;
-
-    UserManagerCompatV17(Context context) {
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-    }
-
-    public long getSerialNumberForUser(UserHandle user) {
-        synchronized (this) {
-            if (mUserToSerialMap != null) {
-                Long serial = mUserToSerialMap.get(user);
-                return serial == null ? 0 : serial;
-            }
-        }
-        return mUserManager.getSerialNumberForUser(user);
-    }
-
-    public UserHandle getUserForSerialNumber(long serialNumber) {
-        synchronized (this) {
-            if (mUsers != null) {
-                return mUsers.get(serialNumber);
-            }
-        }
-        return mUserManager.getUserForSerialNumber(serialNumber);
-    }
-
-    @Override
-    public void enableAndResetCache() {
-        synchronized (this) {
-            mUsers = new LongArrayMap<>();
-            mUserToSerialMap = new HashMap<>();
-            UserHandle myUser = Process.myUserHandle();
-            long serial = mUserManager.getSerialNumberForUser(myUser);
-            mUsers.put(serial, myUser);
-            mUserToSerialMap.put(myUser, serial);
-        }
-    }
-}
-
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index 2774602..45525f5 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -16,12 +16,11 @@
 
 package com.android.launcher3.compat;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
-import android.os.Build;
 import android.os.UserHandle;
+import android.os.UserManager;
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.LongArrayMap;
@@ -31,20 +30,61 @@
 import java.util.HashMap;
 import java.util.List;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class UserManagerCompatVL extends UserManagerCompatV17 {
+public class UserManagerCompatVL extends UserManagerCompat {
     private static final String USER_CREATION_TIME_KEY = "user_creation_time_";
 
+    protected final UserManager mUserManager;
     private final PackageManager mPm;
     private final Context mContext;
 
+    protected LongArrayMap<UserHandle> mUsers;
+    // Create a separate reverse map as LongArrayMap.indexOfValue checks if objects are same
+    // and not {@link Object#equals}
+    protected HashMap<UserHandle, Long> mUserToSerialMap;
+
     UserManagerCompatVL(Context context) {
-        super(context);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mPm = context.getPackageManager();
         mContext = context;
     }
 
     @Override
+    public long getSerialNumberForUser(UserHandle user) {
+        synchronized (this) {
+            if (mUserToSerialMap != null) {
+                Long serial = mUserToSerialMap.get(user);
+                return serial == null ? 0 : serial;
+            }
+        }
+        return mUserManager.getSerialNumberForUser(user);
+    }
+
+    @Override
+    public UserHandle getUserForSerialNumber(long serialNumber) {
+        synchronized (this) {
+            if (mUsers != null) {
+                return mUsers.get(serialNumber);
+            }
+        }
+        return mUserManager.getUserForSerialNumber(serialNumber);
+    }
+
+    @Override
+    public boolean isQuietModeEnabled(UserHandle user) {
+        return false;
+    }
+
+    @Override
+    public boolean isUserUnlocked(UserHandle user) {
+        return true;
+    }
+
+    @Override
+    public boolean isDemoUser() {
+        return false;
+    }
+
+    @Override
     public void enableAndResetCache() {
         synchronized (this) {
             mUsers = new LongArrayMap<>();
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index a3586392..c946235 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -22,7 +22,6 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -31,14 +30,12 @@
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.Build;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Thunk;
 
 import java.util.Arrays;
@@ -89,7 +86,6 @@
      * @param registrationX The x coordinate of the registration point.
      * @param registrationY The y coordinate of the registration point.
      */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
                     final float initialScale, final float finalScaleDps) {
         super(launcher);
@@ -147,9 +143,7 @@
 
         mBlurSizeOutline = getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
 
-        if (Utilities.ATLEAST_LOLLIPOP) {
-            setElevation(getResources().getDimension(R.dimen.drag_elevation));
-        }
+        setElevation(getResources().getDimension(R.dimen.drag_elevation));
     }
 
     /** Sets the scale of the view over the normal workspace icon size. */
@@ -268,14 +262,9 @@
             setColorScale(color, m2);
             m1.postConcat(m2);
 
-            if (Utilities.ATLEAST_LOLLIPOP) {
-                animateFilterTo(m1.getArray());
-            } else {
-                mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
-                invalidate();
-            }
+            animateFilterTo(m1.getArray());
         } else {
-            if (!Utilities.ATLEAST_LOLLIPOP || mCurrentFilter == null) {
+            if (mCurrentFilter == null) {
                 mPaint.setColorFilter(null);
                 invalidate();
             } else {
@@ -284,7 +273,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void animateFilterTo(float[] targetFilter) {
         float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
         mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 52c6abc..876c3c4 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -22,11 +22,9 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.os.Build;
 import android.text.InputType;
 import android.text.Selection;
 import android.util.AttributeSet;
@@ -643,10 +641,8 @@
                 public void onAnimationEnd(Animator animation) {
                     mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
                         .translationX(0)
-                        .setInterpolator(Utilities.ATLEAST_LOLLIPOP ?
-                                AnimationUtils.loadInterpolator(mLauncher,
-                                        android.R.interpolator.fast_out_slow_in)
-                                : new LogDecelerateInterpolator(100, 0));
+                        .setInterpolator(AnimationUtils.loadInterpolator(
+                                mLauncher, android.R.interpolator.fast_out_slow_in));
                     mPageIndicator.playEntryAnimation();
 
                     if (updateAnimationFlag) {
@@ -789,7 +785,6 @@
         }
     };
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public boolean isLayoutRtl() {
         return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
     }
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 7f1790a..1a470ff 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -25,7 +25,6 @@
 import android.view.View;
 import android.widget.TextView;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetHostView;
 import com.android.launcher3.PreloadIconDrawable;
@@ -120,8 +119,7 @@
             width = bounds.width();
             height = bounds.height();
         } else if (mView instanceof LauncherAppWidgetHostView) {
-            DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
-            scale = Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+            scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
             width = (int) (mView.getWidth() * scale);
             height = (int) (mView.getHeight() * scale);
         }
@@ -158,8 +156,7 @@
         int height = mView.getHeight();
 
         if (mView instanceof LauncherAppWidgetHostView) {
-            DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
-            scale = Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+            scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
             width = (int) Math.floor(mView.getWidth() * scale);
             height = (int) Math.floor(mView.getHeight() * scale);
         }
@@ -198,11 +195,10 @@
     public float getScaleAndPosition(Bitmap preview, int[] outPos) {
         float scale = Launcher.getLauncher(mView.getContext())
                 .getDragLayer().getLocationInDragLayer(mView, outPos);
-        DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
         if (mView instanceof LauncherAppWidgetHostView) {
             // App widgets are technically scaled, but are drawn at their expected size -- so the
             // app widget scale should not affect the scale of the preview.
-            scale /= Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+            scale /= ((LauncherAppWidgetHostView) mView).getScaleToFit();
         }
 
         outPos[0] = Math.round(outPos[0] -
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index c59b3a3..3f191bd 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.graphics;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent.ShortcutIconResource;
 import android.content.pm.PackageManager;
@@ -32,13 +31,11 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
-import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 
 /**
@@ -104,7 +101,6 @@
      * Returns a bitmap suitable for the all apps view. The icon is badged for {@param user}.
      * The bitmap is also visually normalized with other icons.
      */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static Bitmap createBadgedIconBitmap(
             Drawable icon, UserHandle user, Context context) {
         float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
@@ -117,8 +113,7 @@
      * Badges the provided icon with the user badge if required.
      */
     public static Bitmap badgeIconForUser(Bitmap icon, UserHandle user, Context context) {
-        if (Utilities.ATLEAST_LOLLIPOP && user != null
-                && !Process.myUserHandle().equals(user)) {
+        if (user != null && !Process.myUserHandle().equals(user)) {
             BitmapDrawable drawable = new FixedSizeBitmapDrawable(icon);
             Drawable badged = context.getPackageManager().getUserBadgedIcon(
                     drawable, user);
@@ -155,7 +150,6 @@
     /**
      * Adds the {@param badge} on top of {@param srcTgt} using the badge dimensions.
      */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static Bitmap badgeWithBitmap(Bitmap srcTgt, Bitmap badge, Context context) {
         int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
         synchronized (sCanvas) {
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index b0d6b2d..c07ab08 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -23,12 +23,10 @@
 import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.os.Build.VERSION_CODES;
 import android.util.Property;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
@@ -38,7 +36,6 @@
 /**
  * A helper class to draw background of a focused view.
  */
-@TargetApi(VERSION_CODES.LOLLIPOP)
 public abstract class FocusIndicatorHelper implements
         OnFocusChangeListener, AnimatorUpdateListener {
 
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 05f43af..6dc5a36 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -123,7 +123,7 @@
                     break;
                 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
                     // Decrement pinned shortcut count
-                    ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
+                    ShortcutKey pinnedShortcut = ShortcutKey.fromItemInfo(item);
                     MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
                     Context context = LauncherAppState.getInstance().getContext();
                     if ((count == null || --count.value == 0)
@@ -155,7 +155,7 @@
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
                 // Increment the count for the given shortcut
-                ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
+                ShortcutKey pinnedShortcut = ShortcutKey.fromItemInfo(item);
                 MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
                 if (count == null) {
                     count = new MutableInt(1);
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 9d693a4..46130fc 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -65,7 +65,7 @@
                     if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                             && isValidShortcut(si) && cn != null
                             && mPackages.contains(cn.getPackageName())) {
-                        iconCache.getTitleAndIcon(si, si.getPromisedIntent(), si.user, si.usingLowResIcon);
+                        iconCache.getTitleAndIcon(si, si.usingLowResIcon);
                         updatedShortcuts.add(si);
                     }
                 }
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index 00470e1..e05bf1e 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -16,27 +16,15 @@
 
 package com.android.launcher3.model;
 
-import android.graphics.Bitmap;
-
-import com.android.launcher3.ItemInfo;
+import com.android.launcher3.ItemInfoWithIcon;
 
 /**
  * Represents a {@link Package} in the widget tray section.
  */
-public class PackageItemInfo extends ItemInfo {
+public class PackageItemInfo extends ItemInfoWithIcon {
 
     /**
-     * A bitmap version of the application icon.
-     */
-    public Bitmap iconBitmap;
-
-    /**
-     * Indicates whether we're using a low res icon.
-     */
-    public boolean usingLowResIcon;
-
-    /**
-     * Package name of the {@link ItemInfo}.
+     * Package name of the {@link PackageItemInfo}.
      */
     public String packageName;
 
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index bafa95b..f5de650 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -251,15 +251,13 @@
                                 si.status = ShortcutInfo.DEFAULT;
                                 infoUpdated = true;
                                 if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
-                                    iconCache.getTitleAndIcon(si, si.getPromisedIntent(),
-                                            si.user, si.usingLowResIcon);
+                                    iconCache.getTitleAndIcon(si, si.usingLowResIcon);
                                 }
                             }
 
                             if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())
                                     && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                                iconCache.getTitleAndIcon(
-                                        si, si.getPromisedIntent(), si.user, si.usingLowResIcon);
+                                iconCache.getTitleAndIcon(si, si.usingLowResIcon);
                                 infoUpdated = true;
                             }
 
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 3750a7e..67bec64 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -61,7 +61,7 @@
         for (ItemInfo itemInfo : dataModel.itemsIdMap) {
             if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
                 ShortcutInfo si = (ShortcutInfo) itemInfo;
-                if (si.getPromisedIntent().getPackage().equals(mPackageName)
+                if (si.getIntent().getPackage().equals(mPackageName)
                         && si.user.equals(mUser)) {
                     idsToWorkspaceShortcutInfos.addToList(si.getDeepShortcutId(), si);
                 }
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 15496b8..a214a29 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -76,8 +76,7 @@
                     && mUser.equals(itemInfo.user)) {
                 ShortcutInfo si = (ShortcutInfo) itemInfo;
                 if (isUserUnlocked) {
-                    ShortcutInfoCompat shortcut =
-                            pinnedShortcuts.get(ShortcutKey.fromShortcutInfo(si));
+                    ShortcutInfoCompat shortcut = pinnedShortcuts.get(ShortcutKey.fromItemInfo(si));
                     // We couldn't verify the shortcut during loader. If its no longer available
                     // (probably due to clear data), delete the workspace item as well
                     if (shortcut == null) {
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index a079301..452dbe2 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -11,7 +11,6 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.util.ComponentKey;
 
 import java.text.Collator;
@@ -32,10 +31,10 @@
     public final String label;
     public final int spanX, spanY;
 
-    public WidgetItem(LauncherAppWidgetProviderInfo info, AppWidgetManagerCompat widgetManager) {
-        super(info.provider, widgetManager.getUser(info));
+    public WidgetItem(LauncherAppWidgetProviderInfo info, PackageManager pm) {
+        super(info.provider, info.getProfile());
 
-        label = Utilities.trim(widgetManager.loadLabel(info));
+        label = Utilities.trim(info.getLabel(pm));
         widgetInfo = info;
         activityInfo = null;
 
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 59dc859..2565985 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -59,16 +59,16 @@
 
         final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
         try {
+            PackageManager pm = context.getPackageManager();
+
             // Widgets
-            AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
-            for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders()) {
+            for (AppWidgetProviderInfo widgetInfo :
+                    AppWidgetManagerCompat.getInstance(context).getAllProviders()) {
                 widgetsAndShortcuts.add(new WidgetItem(
-                        LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo),
-                        widgetManager));
+                        LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo), pm));
             }
 
             // Shortcuts
-            PackageManager pm = context.getPackageManager();
             for (ResolveInfo info :
                     pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) {
                 widgetsAndShortcuts.add(new WidgetItem(info, pm));
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 2f82419..89fd99b 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.provider;
 
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.util.Log;
@@ -42,7 +43,7 @@
      * the first row. The items in the first screen are moved and resized but the carry-forward
      * items are simply deleted.
      */
-    public static boolean prepareScreenZeroToHostQsb(SQLiteDatabase db) {
+    public static boolean prepareScreenZeroToHostQsb(Context context, SQLiteDatabase db) {
         db.beginTransaction();
         try {
             // Get the existing screens
@@ -75,8 +76,8 @@
                 }
             }
 
-            LauncherAppState app = LauncherAppState.getInstance();
-            new LossyScreenMigrationTask(app.getContext(), app.getInvariantDeviceProfile(), db)
+            new LossyScreenMigrationTask(
+                    context, LauncherAppState.getInstance().getInvariantDeviceProfile(), db)
                     .migrateScreen0();
             db.setTransactionSuccessful();
             return true;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
index acc632c..dac2160 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -25,8 +25,6 @@
 import android.os.UserHandle;
 
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.compat.DeferredLauncherActivityInfo;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 
 /**
@@ -122,8 +120,4 @@
     public String toString() {
         return mShortcutInfo.toString();
     }
-
-    public LauncherActivityInfoCompat getActivityInfo(Context context) {
-        return new DeferredLauncherActivityInfo(getActivity(), getUserHandle(), context);
-    }
 }
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index 8f72666..e86bfb2 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -4,7 +4,7 @@
 import android.content.Intent;
 import android.os.UserHandle;
 
-import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.ItemInfo;
 import com.android.launcher3.util.ComponentKey;
 
 /**
@@ -32,7 +32,7 @@
         return new ShortcutKey(intent.getPackage(), user, shortcutId);
     }
 
-    public static ShortcutKey fromShortcutInfo(ShortcutInfo info) {
-        return fromIntent(info.getPromisedIntent(), info.user);
+    public static ShortcutKey fromItemInfo(ItemInfo info) {
+        return fromIntent(info.getIntent(), info.user);
     }
 }
diff --git a/src/com/android/launcher3/util/CircleRevealOutlineProvider.java b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
index c192120..9fe5147 100644
--- a/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
+++ b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
@@ -16,10 +16,6 @@
 
 package com.android.launcher3.util;
 
-import android.annotation.TargetApi;
-import android.os.Build;
-
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class CircleRevealOutlineProvider extends RevealOutlineAnimation {
 
     private int mCenterX;
diff --git a/src/com/android/launcher3/util/ConfigMonitor.java b/src/com/android/launcher3/util/ConfigMonitor.java
index bdb1639..2489d30 100644
--- a/src/com/android/launcher3/util/ConfigMonitor.java
+++ b/src/com/android/launcher3/util/ConfigMonitor.java
@@ -23,8 +23,6 @@
 import android.content.res.Configuration;
 import android.util.Log;
 
-import com.android.launcher3.Utilities;
-
 /**
  * {@link BroadcastReceiver} which watches configuration changes and
  * restarts the process in case changes which affect the device profile occur.
@@ -40,13 +38,13 @@
 
         Configuration config = context.getResources().getConfiguration();
         mFontScale = config.fontScale;
-        mDensity = getDensity(config);
+        mDensity = config.densityDpi;
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
         Configuration config = context.getResources().getConfiguration();
-        if (mFontScale != config.fontScale || mDensity != getDensity(config)) {
+        if (mFontScale != config.fontScale || mDensity != config.densityDpi) {
             Log.d("ConfigMonitor", "Configuration changed, restarting launcher");
             mContext.unregisterReceiver(this);
             android.os.Process.killProcess(android.os.Process.myPid());
@@ -56,8 +54,4 @@
     public void register() {
         mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
     }
-
-    private static int getDensity(Configuration config) {
-        return Utilities.ATLEAST_JB_MR1 ? config.densityDpi : 0;
-    }
 }
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index b6e0e6e..42de284 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -100,7 +100,7 @@
             @Override
             public boolean matches(ItemInfo info, ComponentName cn) {
                 return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
-                        keys.contains(ShortcutKey.fromShortcutInfo((ShortcutInfo) info));
+                        keys.contains(ShortcutKey.fromItemInfo(info));
             }
         };
     }
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 2d9e368..ce42bcd 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -211,9 +210,6 @@
      * Verifies that entries corresponding to {@param users} exist and removes all invalid entries.
      */
     public static void processAllUsers(List<UserHandle> users, Context context) {
-        if (!Utilities.ATLEAST_LOLLIPOP) {
-            return;
-        }
         UserManagerCompat userManager = UserManagerCompat.getInstance(context);
         HashSet<String> validKeys = new HashSet<String>();
         for (UserHandle user : users) {
diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
index 8eea28b..9452fbd 100644
--- a/src/com/android/launcher3/util/PendingRequestArgs.java
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -15,7 +15,9 @@
  */
 package com.android.launcher3.util;
 
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -57,9 +59,8 @@
         mArg1 = parcel.readInt();
         mObjectType = parcel.readInt();
         if (parcel.readInt() != 0) {
-            mObject = mObjectType == TYPE_INTENT
-                    ? Intent.CREATOR.createFromParcel(parcel)
-                    : new LauncherAppWidgetProviderInfo(parcel);
+            mObject = (mObjectType == TYPE_INTENT ? Intent.CREATOR : AppWidgetProviderInfo.CREATOR)
+                    .createFromParcel(parcel);
         } else {
             mObject = null;
         }
@@ -86,8 +87,10 @@
         }
     }
 
-    public LauncherAppWidgetProviderInfo getWidgetProvider() {
-        return mObjectType == TYPE_APP_WIDGET ? (LauncherAppWidgetProviderInfo) mObject : null;
+    public LauncherAppWidgetProviderInfo getWidgetProvider(Context context) {
+        return mObjectType == TYPE_APP_WIDGET ?
+                LauncherAppWidgetProviderInfo.fromProviderInfo(
+                        context, (AppWidgetProviderInfo) mObject) : null;
     }
 
     public int getWidgetId() {
@@ -103,7 +106,7 @@
     }
 
     public static PendingRequestArgs forWidgetInfo(
-            int appWidgetId, LauncherAppWidgetProviderInfo widgetInfo, ItemInfo info) {
+            int appWidgetId, AppWidgetProviderInfo widgetInfo, ItemInfo info) {
         PendingRequestArgs args = new PendingRequestArgs(appWidgetId, TYPE_APP_WIDGET, widgetInfo);
         args.copyFrom(info);
         return args;
diff --git a/src/com/android/launcher3/util/PillRevealOutlineProvider.java b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
index 3f1e11a..1a3b486 100644
--- a/src/com/android/launcher3/util/PillRevealOutlineProvider.java
+++ b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
@@ -16,12 +16,9 @@
 
 package com.android.launcher3.util;
 
-import android.annotation.TargetApi;
 import android.graphics.Rect;
-import android.os.Build;
 import android.view.ViewOutlineProvider;
 
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 /**
  * A {@link ViewOutlineProvider} that animates a reveal in a "pill" shape.
  * A pill is simply a round rect, but we assume the width is greater than
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index f800ac4..7968684 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -16,15 +16,11 @@
 package com.android.launcher3.widget;
 
 import android.appwidget.AppWidgetHostView;
-import android.content.Context;
 import android.os.Bundle;
-import android.os.Parcelable;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.PendingAddItemInfo;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
 
 /**
  * Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}.
@@ -38,14 +34,14 @@
     public AppWidgetHostView boundWidget;
     public Bundle bindOptions = null;
 
-    public PendingAddWidgetInfo(Context context, LauncherAppWidgetProviderInfo i) {
+    public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i) {
         if (i.isCustomWidget) {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
         } else {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
         }
         this.info = i;
-        user = AppWidgetManagerCompat.getInstance(context).getUser(i);
+        user = i.getUser();
         componentName = i.provider;
         previewImage = i.previewImage;
         icon = i.icon;
@@ -55,8 +51,4 @@
         minSpanX = i.minSpanX;
         minSpanY = i.minSpanY;
     }
-
-    public boolean isCustomWidget() {
-        return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 07f59a5..5eeae87 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -140,7 +140,7 @@
         if (item.activityInfo != null) {
             setTag(new PendingAddShortcutInfo(item.activityInfo));
         } else {
-            setTag(new PendingAddWidgetInfo(mLauncher, item.widgetInfo));
+            setTag(new PendingAddWidgetInfo(item.widgetInfo));
         }
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index b196053..56112b2 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -10,12 +10,9 @@
 import android.view.View;
 
 import com.android.launcher3.AppWidgetResizeFrame;
-import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
-import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
@@ -154,27 +151,24 @@
     }
 
     public static Bundle getDefaultOptionsForWidget(Context context, PendingAddWidgetInfo info) {
-        Bundle options = null;
-        if (Utilities.ATLEAST_JB_MR1) {
-            Rect rect = new Rect();
-            AppWidgetResizeFrame.getWidgetSizeRanges(context, info.spanX, info.spanY, rect);
-            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context,
-                    info.componentName, null);
+        Rect rect = new Rect();
+        AppWidgetResizeFrame.getWidgetSizeRanges(context, info.spanX, info.spanY, rect);
+        Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context,
+                info.componentName, null);
 
-            float density = context.getResources().getDisplayMetrics().density;
-            int xPaddingDips = (int) ((padding.left + padding.right) / density);
-            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+        float density = context.getResources().getDisplayMetrics().density;
+        int xPaddingDips = (int) ((padding.left + padding.right) / density);
+        int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
 
-            options = new Bundle();
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                    rect.left - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                    rect.top - yPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                    rect.right - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                    rect.bottom - yPaddingDips);
-        }
+        Bundle options = new Bundle();
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+                rect.left - xPaddingDips);
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+                rect.top - yPaddingDips);
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+                rect.right - xPaddingDips);
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+                rect.bottom - yPaddingDips);
         return options;
     }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index a5846ec..f18313f 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -15,9 +15,7 @@
  */
 package com.android.launcher3.widget;
 
-import android.annotation.TargetApi;
 import android.content.Context;
-import android.os.Build;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.util.Log;
@@ -29,7 +27,6 @@
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.model.PackageItemInfo;
@@ -152,7 +149,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     @Override
     public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         if (DEBUG) {
@@ -165,11 +161,7 @@
 
         // if the end padding is 0, then container view (horizontal scroll view) doesn't respect
         // the end of the linear layout width + the start padding and doesn't allow scrolling.
-        if (Utilities.ATLEAST_JB_MR1) {
-            cellList.setPaddingRelative(mIndent, 0, 1, 0);
-        } else {
-            cellList.setPadding(mIndent, 0, 1, 0);
-        }
+        cellList.setPaddingRelative(mIndent, 0, 1, 0);
 
         return new WidgetsRowViewHolder(container);
     }
diff --git a/tests/Android.mk b/tests/Android.mk
index 466146e..5103ced 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -17,9 +17,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-#LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
 
-#LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 21
diff --git a/tests/src/com/android/launcher3/BindWidgetTest.java b/tests/src/com/android/launcher3/BindWidgetTest.java
index 6be2522..72533e7 100644
--- a/tests/src/com/android/launcher3/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/BindWidgetTest.java
@@ -1,6 +1,5 @@
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHost;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -9,7 +8,6 @@
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
-import android.os.Build;
 import android.os.Bundle;
 import android.support.test.uiautomator.UiSelector;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -33,7 +31,6 @@
  * Note running these tests will clear the workspace on the device.
  */
 @LargeTest
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class BindWidgetTest extends LauncherInstrumentationTestCase {
 
     private ContentResolver mResolver;
@@ -264,13 +261,13 @@
         item.spanY = info.minSpanY;
         item.minSpanX = info.minSpanX;
         item.minSpanY = info.minSpanY;
-        item.user = mWidgetManager.getUser(info);
+        item.user = info.getUser();
         item.cellX = 0;
         item.cellY = 1;
         item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
 
         if (bindWidget) {
-            PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(mTargetContext, info);
+            PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(info);
             pendingInfo.spanX = item.spanX;
             pendingInfo.spanY = item.spanY;
             pendingInfo.minSpanX = item.minSpanX;
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index f23a574..1d092ab 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -8,6 +8,7 @@
 import android.graphics.Bitmap.Config;
 import android.os.Process;
 import android.os.UserHandle;
+import android.support.annotation.NonNull;
 import android.support.test.InstrumentationRegistry;
 import android.test.ProviderTestCase2;
 
@@ -24,6 +25,7 @@
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.TestLauncherProvider;
 
 import org.mockito.ArgumentCaptor;
@@ -184,9 +186,10 @@
         }
 
         @Override
-        protected CacheEntry cacheLocked(ComponentName componentName,
-                LauncherActivityInfoCompat info, UserHandle user,
-                boolean usePackageIcon, boolean useLowResIcon) {
+        protected CacheEntry cacheLocked(
+                @NonNull ComponentName componentName,
+                @NonNull Provider<LauncherActivityInfoCompat> infoProvider,
+                UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
             CacheEntry entry = mCache.get(new ComponentKey(componentName, user));
             if (entry == null) {
                 entry = new CacheEntry();