Merge "Removing unnecessary intent-filter construction" into ub-launcher3-burnaby
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979..67abf65 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,6 +20,8 @@
 import android.graphics.Bitmap.Config;
 import android.opengl.GLUtils;
 
+import com.android.launcher3.util.Thunk;
+
 import junit.framework.Assert;
 
 import java.util.HashMap;
@@ -82,7 +84,7 @@
         return mIsUploading;
     }
 
-    private static class BorderKey implements Cloneable {
+    @Thunk static class BorderKey implements Cloneable {
         public boolean vertical;
         public Config config;
         public int length;
diff --git a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java b/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
index 72f2d7e..a5e951c 100644
--- a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
+++ b/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
@@ -35,6 +35,8 @@
 import android.widget.ListAdapter;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -50,7 +52,7 @@
     private final LayoutInflater mInflater;
     private final PackageManager mPackageManager;
 
-    private List<LiveWallpaperTile> mWallpapers;
+    @Thunk List<LiveWallpaperTile> mWallpapers;
 
     @SuppressWarnings("unchecked")
     public LiveWallpaperListAdapter(Context context) {
@@ -109,8 +111,8 @@
     }
 
     public static class LiveWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
-        private Drawable mThumbnail;
-        private WallpaperInfo mInfo;
+        @Thunk Drawable mThumbnail;
+        @Thunk WallpaperInfo mInfo;
         public LiveWallpaperTile(Drawable thumbnail, WallpaperInfo info, Intent intent) {
             mThumbnail = thumbnail;
             mInfo = info;
diff --git a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
index 27e65aa..16bde33 100644
--- a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
@@ -32,6 +32,8 @@
 import android.widget.ListAdapter;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -46,7 +48,7 @@
             new ArrayList<ThirdPartyWallpaperTile>();
 
     public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
-        private ResolveInfo mResolveInfo;
+        @Thunk ResolveInfo mResolveInfo;
         public ThirdPartyWallpaperTile(ResolveInfo resolveInfo) {
             mResolveInfo = resolveInfo;
         }
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
index a3a3c53..5b2943a 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
@@ -44,6 +44,7 @@
 import com.android.gallery3d.common.BitmapCropTask;
 import com.android.gallery3d.common.BitmapUtils;
 import com.android.gallery3d.common.Utils;
+import com.android.launcher3.util.Thunk;
 import com.android.photos.BitmapRegionTileSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource.InBitmapProvider;
@@ -78,10 +79,10 @@
 
     private HandlerThread mLoaderThread;
     private Handler mLoaderHandler;
-    private LoadRequest mCurrentLoadRequest;
+    @Thunk LoadRequest mCurrentLoadRequest;
     private byte[] mTempStorageForDecoding = new byte[16 * 1024];
     // A weak-set of reusable bitmaps
-    private Set<Bitmap> mReusableBitmaps =
+    @Thunk Set<Bitmap> mReusableBitmaps =
             Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
 
     @Override
@@ -220,7 +221,7 @@
         return false;
     }
 
-    private void addReusableBitmap(TileSource src) {
+    @Thunk void addReusableBitmap(TileSource src) {
         synchronized (mReusableBitmaps) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
                     && src instanceof BitmapRegionTileSource) {
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index d16fc31..1364df3 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -70,6 +70,7 @@
 import com.android.gallery3d.common.BitmapCropTask;
 import com.android.gallery3d.common.BitmapUtils;
 import com.android.gallery3d.common.Utils;
+import com.android.launcher3.util.Thunk;
 import com.android.photos.BitmapRegionTileSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource;
 import com.android.photos.views.TiledImageRenderer.TileSource;
@@ -88,21 +89,21 @@
     private static final String SELECTED_INDEX = "SELECTED_INDEX";
     private static final int FLAG_POST_DELAY_MILLIS = 200;
 
-    private View mSelectedTile;
-    private boolean mIgnoreNextTap;
-    private OnClickListener mThumbnailOnClickListener;
+    @Thunk View mSelectedTile;
+    @Thunk boolean mIgnoreNextTap;
+    @Thunk OnClickListener mThumbnailOnClickListener;
 
-    private LinearLayout mWallpapersView;
-    private HorizontalScrollView mWallpaperScrollContainer;
+    @Thunk LinearLayout mWallpapersView;
+    @Thunk HorizontalScrollView mWallpaperScrollContainer;
 
-    private ActionMode.Callback mActionModeCallback;
-    private ActionMode mActionMode;
+    @Thunk ActionMode.Callback mActionModeCallback;
+    @Thunk ActionMode mActionMode;
 
-    private View.OnLongClickListener mLongClickListener;
+    @Thunk View.OnLongClickListener mLongClickListener;
 
     ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>();
     private SavedWallpaperImages mSavedImages;
-    private int mSelectedIndex = -1;
+    @Thunk int mSelectedIndex = -1;
 
     public static abstract class WallpaperTileInfo {
         protected View mView;
@@ -135,7 +136,7 @@
     public static class UriWallpaperInfo extends WallpaperTileInfo {
         private Uri mUri;
         private boolean mFirstClick = true;
-        private BitmapRegionTileSource.UriBitmapSource mBitmapSource;
+        @Thunk BitmapRegionTileSource.UriBitmapSource mBitmapSource;
         public UriWallpaperInfo(Uri uri) {
             mUri = uri;
         }
@@ -337,7 +338,7 @@
         }, FLAG_POST_DELAY_MILLIS);
     }
 
-    private void changeWallpaperFlags(boolean visible) {
+    @Thunk void changeWallpaperFlags(boolean visible) {
         int desiredWallpaperFlag = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
         int currentWallpaperFlag = getWindow().getAttributes().flags
                 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -635,7 +636,7 @@
         };
     }
 
-    private void selectTile(View v) {
+    @Thunk void selectTile(View v) {
         if (mSelectedTile != null) {
             mSelectedTile.setSelected(false);
             mSelectedTile = null;
@@ -649,7 +650,7 @@
                 getString(R.string.announce_selection, v.getContentDescription()));
     }
 
-    private void initializeScrollForRtl() {
+    @Thunk void initializeScrollForRtl() {
         if (mWallpaperScrollContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
             final ViewTreeObserver observer = mWallpaperScrollContainer.getViewTreeObserver();
             observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@@ -704,7 +705,7 @@
         mSelectedIndex = savedInstanceState.getInt(SELECTED_INDEX, -1);
     }
 
-    private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
+    @Thunk void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
             boolean addLongPressHandler) {
         for (int i = 0; i < adapter.getCount(); i++) {
             FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
@@ -719,7 +720,7 @@
         }
     }
 
-    private void updateTileIndices() {
+    @Thunk void updateTileIndices() {
         LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
         final int childCount = masterWallpaperList.getChildCount();
         final Resources res = getResources();
@@ -760,13 +761,13 @@
         }
     }
 
-    private static Point getDefaultThumbnailSize(Resources res) {
+    @Thunk static Point getDefaultThumbnailSize(Resources res) {
         return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
                 res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
 
     }
 
-    private static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
+    @Thunk static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
             Resources res, int resId, int rotation, boolean leftAligned) {
         int width = size.x;
         int height = size.y;
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
index f9b7ab4..39a73b9 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
@@ -30,6 +30,7 @@
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLCanvas;
 import com.android.gallery3d.glrenderer.UploadedTexture;
+import com.android.launcher3.util.Thunk;
 import com.android.photos.views.Pools.Pool;
 import com.android.photos.views.Pools.SynchronizedPool;
 
@@ -67,12 +68,12 @@
     private static final int STATE_RECYCLING = 0x20;
     private static final int STATE_RECYCLED = 0x40;
 
-    private static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
+    @Thunk static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
 
     // TILE_SIZE must be 2^N
-    private int mTileSize;
+    @Thunk int mTileSize;
 
-    private TileSource mModel;
+    @Thunk TileSource mModel;
     private BasicTexture mPreview;
     protected int mLevelCount;  // cache the value of mScaledBitmaps.length
 
@@ -82,7 +83,7 @@
     // half size of the previous one). If the value is in [0, mLevelCount), we
     // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value
     // is mLevelCount
-    private int mLevel = 0;
+    @Thunk int mLevel = 0;
 
     private int mOffsetX;
     private int mOffsetY;
@@ -96,10 +97,10 @@
     private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>();
 
     // The following three queue are guarded by mQueueLock
-    private final Object mQueueLock = new Object();
+    @Thunk final Object mQueueLock = new Object();
     private final TileQueue mRecycledQueue = new TileQueue();
     private final TileQueue mUploadQueue = new TileQueue();
-    private final TileQueue mDecodeQueue = new TileQueue();
+    @Thunk final TileQueue mDecodeQueue = new TileQueue();
 
     // The width and height of the full-sized bitmap
     protected int mImageWidth = SIZE_UNKNOWN;
@@ -489,7 +490,7 @@
        }
     }
 
-    private void decodeTile(Tile tile) {
+    @Thunk void decodeTile(Tile tile) {
         synchronized (mQueueLock) {
             if (tile.mTileState != STATE_IN_QUEUE) {
                 return;
@@ -556,7 +557,7 @@
         mActiveTiles.put(key, tile);
     }
 
-    private Tile getTile(int x, int y, int level) {
+    @Thunk Tile getTile(int x, int y, int level) {
         return mActiveTiles.get(makeTileKey(x, y, level));
     }
 
@@ -748,7 +749,7 @@
         }
     }
 
-    private static class TileQueue {
+    @Thunk static class TileQueue {
         private Tile mHead;
 
         public Tile pop() {
@@ -786,7 +787,7 @@
         }
     }
 
-    private class TileDecoder extends Thread {
+    @Thunk class TileDecoder extends Thread {
 
         public void finishAndWait() {
             interrupt();
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
index 56ee7a6..7e3e1a9 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
@@ -33,6 +33,7 @@
 
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLES20Canvas;
+import com.android.launcher3.util.Thunk;
 import com.android.photos.views.TiledImageRenderer.TileSource;
 
 import javax.microedition.khronos.egl.EGLConfig;
@@ -43,8 +44,8 @@
  */
 public class TiledImageView extends FrameLayout {
 
-    private GLSurfaceView mGLSurfaceView;
-    private boolean mInvalPending = false;
+    @Thunk GLSurfaceView mGLSurfaceView;
+    @Thunk boolean mInvalPending = false;
     private FrameCallback mFrameCallback;
 
     protected static class ImageRendererWrapper {
@@ -203,7 +204,7 @@
         }
     }
 
-    private class TileRenderer implements Renderer {
+    @Thunk class TileRenderer implements Renderer {
 
         private GLES20Canvas mCanvas;
 
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index ce092bf..ea12fa3 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -33,6 +33,8 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.List;
 
 
@@ -49,12 +51,12 @@
     private static final int LIST_LAYOUT = 1;
     private static final int USE_LAYOUT = GRID_LAYOUT;
 
-    private Launcher mLauncher;
-    private AlphabeticalAppsList mApps;
+    @Thunk Launcher mLauncher;
+    @Thunk AlphabeticalAppsList mApps;
     private RecyclerView.Adapter mAdapter;
     private RecyclerView.LayoutManager mLayoutManager;
     private RecyclerView.ItemDecoration mItemDecoration;
-    private AppsContainerRecyclerView mAppsListView;
+    @Thunk AppsContainerRecyclerView mAppsListView;
     private EditText mSearchBar;
     private int mNumAppsPerRow;
     private Point mLastTouchDownPos = new Point();
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index bf36812..1955547 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -38,7 +38,6 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.GridLayout;
 import android.widget.ImageView;
 import android.widget.Toast;
@@ -46,11 +45,10 @@
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.FocusHelper.PagedViewKeyListener;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
-import java.util.List;
 
 /**
  * A simple callback interface which also provides the results of the task.
@@ -154,7 +152,7 @@
     private ContentType mContentType = ContentType.Widgets;
 
     // Refs
-    private Launcher mLauncher;
+    @Thunk Launcher mLauncher;
     private DragController mDragController;
     private final LayoutInflater mLayoutInflater;
     private final PackageManager mPackageManager;
@@ -170,8 +168,7 @@
 
     // Dimens
     private int mContentWidth, mContentHeight;
-    private int mWidgetCountX, mWidgetCountY;
-    private PagedViewCellLayout mWidgetSpacingLayout;
+    @Thunk int mWidgetCountX, mWidgetCountY;
     private int mNumWidgetPages;
 
     // Previews & outlines
@@ -195,10 +192,10 @@
     private Toast mWidgetInstructionToast;
 
     // Deferral of loading widget previews during launcher transitions
-    private boolean mInTransition;
+    @Thunk boolean mInTransition;
     private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems =
         new ArrayList<AsyncTaskPageData>();
-    private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
+    @Thunk ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
         new ArrayList<Runnable>();
 
     WidgetPreviewLoader mWidgetPreviewLoader;
@@ -219,7 +216,6 @@
         mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
         mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
         a.recycle();
-        mWidgetSpacingLayout = new PagedViewCellLayout(getContext());
 
         // The padding on the non-matched dimension for the default widget preview icons
         // (top + bottom)
@@ -316,9 +312,6 @@
         // Force a measure to update recalculate the gaps
         mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
         mContentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-        int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
-        int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-        mWidgetSpacingLayout.measure(widthSpec, heightSpec);
 
         final boolean hostIsTransitioning = getTabHost().isInTransition();
         int page = getPageForComponent(mSaveInstanceStateItemIndex);
@@ -596,13 +589,11 @@
 
             FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
             float minScale = 1.25f;
-            int maxWidth, maxHeight;
-            maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
-            maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]);
+            int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
 
             int[] previewSizeBeforeScale = new int[1];
             preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
-                    spanX, spanY, maxWidth, maxHeight, null, previewSizeBeforeScale);
+                    maxWidth, null, previewSizeBeforeScale);
 
             // Compare the size of the drag preview to the preview in the AppsCustomize tray
             int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
@@ -917,7 +908,7 @@
     /**
      * Creates and executes a new AsyncTask to load a page of widget previews.
      */
-    private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets,
+    @Thunk void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets,
             int cellWidth, int cellHeight, int cellCountX) {
 
         // Prune all tasks that are no longer needed
@@ -1075,8 +1066,7 @@
                     maxPreviewHeight = maxSize[1];
                 }
 
-                getWidgetPreviewLoader().setPreviewSize(
-                        maxPreviewWidth, maxPreviewHeight, mWidgetSpacingLayout);
+                getWidgetPreviewLoader().setPreviewSize(maxPreviewWidth, maxPreviewHeight);
                 if (immediate) {
                     AsyncTaskPageData data = new AsyncTaskPageData(page, items,
                             maxPreviewWidth, maxPreviewHeight, null, null, getWidgetPreviewLoader());
@@ -1094,7 +1084,7 @@
             }
         });
     }
-    private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
+    @Thunk void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
             AsyncTaskPageData data) {
         // loadWidgetPreviewsInBackground can be called without a task to load a set of widget
         // previews synchronously
@@ -1120,7 +1110,7 @@
         }
     }
 
-    private void onSyncWidgetPageItems(AsyncTaskPageData data, boolean immediatelySyncItems) {
+    @Thunk void onSyncWidgetPageItems(AsyncTaskPageData data, boolean immediatelySyncItems) {
         if (!immediatelySyncItems && mInTransition) {
             mDeferredSyncWidgetPageItems.add(data);
             return;
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 6a4495e..5895cbf 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -11,7 +11,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
+
 import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.util.Thunk;
 
 
 /**
@@ -108,21 +110,21 @@
     }
 
     private LayoutInflater mLayoutInflater;
-    private AlphabeticalAppsList mApps;
+    @Thunk AlphabeticalAppsList mApps;
     private GridSpanSizer mGridSizer;
     private GridItemDecoration mItemDecoration;
     private View.OnTouchListener mTouchListener;
     private View.OnClickListener mIconClickListener;
     private View.OnLongClickListener mIconLongClickListener;
-    private int mAppsPerRow;
-    private boolean mIsRtl;
+    @Thunk int mAppsPerRow;
+    @Thunk boolean mIsRtl;
     private String mEmptySearchText;
 
     // Section drawing
-    private int mPaddingStart;
-    private int mStartMargin;
-    private Paint mSectionTextPaint;
-    private Rect mTmpBounds = new Rect();
+    @Thunk int mPaddingStart;
+    @Thunk int mStartMargin;
+    @Thunk Paint mSectionTextPaint;
+    @Thunk Rect mTmpBounds = new Rect();
 
 
     public AppsGridAdapter(Context context, AlphabeticalAppsList apps, int appsPerRow,
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 908bd3d..cbab08b 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -37,6 +37,7 @@
 
 import com.android.launcher3.LauncherProvider.SqlArguments;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -114,8 +115,8 @@
     private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
             "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
 
-    private final Context mContext;
-    private final AppWidgetHost mAppWidgetHost;
+    @Thunk final Context mContext;
+    @Thunk final AppWidgetHost mAppWidgetHost;
     protected final LayoutParserCallback mCallback;
 
     protected final PackageManager mPackageManager;
@@ -125,7 +126,7 @@
     private final int mHotseatAllAppsRank;
 
     private final long[] mTemp = new long[2];
-    private final ContentValues mValues;
+    @Thunk final ContentValues mValues;
     protected final String mRootTag;
 
     protected SQLiteDatabase mDb;
@@ -648,7 +649,7 @@
         long insertAndCheck(SQLiteDatabase db, ContentValues values);
     }
 
-    private static void copyInteger(ContentValues from, ContentValues to, String key) {
+    @Thunk static void copyInteger(ContentValues from, ContentValues to, String key) {
         to.put(key, from.getAsInteger(key));
     }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index c57090d..eb2aa54 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -55,6 +55,7 @@
 
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -68,18 +69,18 @@
     static final String TAG = "CellLayout";
 
     private Launcher mLauncher;
-    private int mCellWidth;
-    private int mCellHeight;
+    @Thunk int mCellWidth;
+    @Thunk int mCellHeight;
     private int mFixedCellWidth;
     private int mFixedCellHeight;
 
-    private int mCountX;
-    private int mCountY;
+    @Thunk int mCountX;
+    @Thunk int mCountY;
 
     private int mOriginalWidthGap;
     private int mOriginalHeightGap;
-    private int mWidthGap;
-    private int mHeightGap;
+    @Thunk int mWidthGap;
+    @Thunk int mHeightGap;
     private int mMaxGap;
     private boolean mDropPending = false;
     private boolean mIsDragTarget = true;
@@ -87,7 +88,7 @@
     // These are temporary variables to prevent having to allocate a new object just to
     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
     private final int[] mTmpXY = new int[2];
-    private final int[] mTmpPoint = new int[2];
+    @Thunk final int[] mTmpPoint = new int[2];
     int[] mTempLocation = new int[2];
 
     boolean[][] mOccupied;
@@ -124,8 +125,8 @@
 
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
-    private Rect[] mDragOutlines = new Rect[4];
-    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
+    @Thunk Rect[] mDragOutlines = new Rect[4];
+    @Thunk float[] mDragOutlineAlphas = new float[mDragOutlines.length];
     private InterruptibleInOutAnimator[] mDragOutlineAnims =
             new InterruptibleInOutAnimator[mDragOutlines.length];
 
@@ -135,7 +136,7 @@
 
     private final FastBitmapView mTouchFeedbackView;
 
-    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
+    @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
             HashMap<CellLayout.LayoutParams, Animator>();
     private HashMap<View, ReorderPreviewAnimation>
             mShakeAnimators = new HashMap<View, ReorderPreviewAnimation>();
@@ -166,7 +167,7 @@
 
     private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
     private static final int REORDER_ANIMATION_DURATION = 150;
-    private float mReorderPreviewAnimationMagnitude;
+    @Thunk float mReorderPreviewAnimationMagnitude;
 
     private ArrayList<View> mIntersectingViews = new ArrayList<View>();
     private Rect mOccupiedRect = new Rect();
@@ -184,8 +185,8 @@
     private boolean mUseTouchHelper = false;
     OnClickListener mOldClickListener = null;
     OnClickListener mOldWorkspaceListener = null;
-    private int mDownX = 0;
-    private int mDownY = 0;
+    @Thunk int mDownX = 0;
+    @Thunk int mDownY = 0;
 
     public CellLayout(Context context) {
         this(context, null);
@@ -2550,7 +2551,7 @@
             }
         }
 
-        private void completeAnimationImmediately() {
+        @Thunk void completeAnimationImmediately() {
             if (a != null) {
                 a.cancel();
             }
@@ -2871,7 +2872,7 @@
         return mItemPlacementDirty;
     }
 
-    private class ItemConfiguration {
+    @Thunk class ItemConfiguration {
         HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
         private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>();
         ArrayList<View> sortedViews = new ArrayList<View>();
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 8114979..10ca6a3 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -18,9 +18,11 @@
 
 import android.view.View;
 
+import com.android.launcher3.util.Thunk;
+
 public class CheckLongPressHelper {
-    private View mView;
-    private boolean mHasPerformedLongPress;
+    @Thunk View mView;
+    @Thunk boolean mHasPerformedLongPress;
     private CheckForLongPress mPendingCheckForLongPress;
 
     class CheckForLongPress implements Runnable {
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
index fe2fbd7..3164179 100644
--- a/src/com/android/launcher3/CommonAppTypeParser.java
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -91,8 +91,8 @@
     private class MyLayoutParser extends DefaultLayoutParser {
 
         public MyLayoutParser() {
-            super(mContext, null, CommonAppTypeParser.this,
-                    mContext.getResources(), mResId, TAG_RESOLVE, 0);
+            super(CommonAppTypeParser.this.mContext, null, CommonAppTypeParser.this,
+                    CommonAppTypeParser.this.mContext.getResources(), mResId, TAG_RESOLVE, 0);
         }
 
         @Override
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index 6c3008b..7b91c67 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -13,6 +13,7 @@
 import android.util.Log;
 
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -57,7 +58,7 @@
         return getFolderElementsMap(mSourceRes);
     }
 
-    private HashMap<String, TagParser> getFolderElementsMap(Resources res) {
+    @Thunk HashMap<String, TagParser> getFolderElementsMap(Resources res) {
         HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
         parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
         parsers.put(TAG_SHORTCUT, new UriShortcutParser(res));
@@ -89,7 +90,7 @@
     /**
      * AppShortcutParser which also supports adding URI based intents
      */
-    private class AppShortcutWithUriParser extends AppShortcutParser {
+    @Thunk class AppShortcutWithUriParser extends AppShortcutParser {
 
         @Override
         protected long invalidPackageOrClass(XmlResourceParser parser) {
@@ -231,7 +232,7 @@
     /**
      * A parser which adds a folder whose contents come from partner apk.
      */
-    private class PartnerFolderParser implements TagParser {
+    @Thunk class PartnerFolderParser implements TagParser {
 
         @Override
         public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
@@ -257,7 +258,7 @@
     /**
      * An extension of FolderParser which allows adding items from a different xml.
      */
-    private class MyFolderParser extends FolderParser {
+    @Thunk class MyFolderParser extends FolderParser {
 
         @Override
         public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
index a2d121d..eb7c26a 100644
--- a/src/com/android/launcher3/DeferredHandler.java
+++ b/src/com/android/launcher3/DeferredHandler.java
@@ -22,6 +22,8 @@
 import android.os.MessageQueue;
 import android.util.Pair;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.LinkedList;
 import java.util.ListIterator;
 
@@ -33,11 +35,11 @@
  * This class is fifo.
  */
 public class DeferredHandler {
-    private LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
+    @Thunk LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
     private MessageQueue mMessageQueue = Looper.myQueue();
     private Impl mHandler = new Impl();
 
-    private class Impl extends Handler implements MessageQueue.IdleHandler {
+    @Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
         public void handleMessage(Message msg) {
             Pair<Runnable, Integer> p;
             Runnable r;
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 1ada1a9..1f0dad2 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -41,6 +41,7 @@
 import android.view.animation.LinearInterpolator;
 
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Thunk;
 
 public class DeleteDropTarget extends ButtonDropTarget {
     private static int DELETE_ANIMATION_DURATION = 285;
@@ -56,7 +57,7 @@
     private TransitionDrawable mRemoveDrawable;
     private TransitionDrawable mCurrentDrawable;
 
-    private boolean mWaitingForUninstall = false;
+    @Thunk boolean mWaitingForUninstall = false;
 
     public DeleteDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -272,7 +273,7 @@
         return false;
     }
 
-    private void completeDrop(DragObject d) {
+    @Thunk void completeDrop(DragObject d) {
         ItemInfo item = (ItemInfo) d.dragInfo;
         boolean wasWaitingForUninstall = mWaitingForUninstall;
         mWaitingForUninstall = false;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bc9ef76..b4d225e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -38,6 +38,8 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -449,7 +451,7 @@
         updateAvailableDimensions(context);
     }
 
-    private float dist(PointF p0, PointF p1) {
+    @Thunk float dist(PointF p0, PointF p1) {
         return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
                 (p1.y-p0.y)*(p1.y-p0.y));
     }
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index 8dc6e18..eb16861 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -34,6 +34,8 @@
 import android.view.ViewConfiguration;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -63,7 +65,7 @@
 
     private static final float MAX_FLING_DEGREES = 35f;
 
-    private Launcher mLauncher;
+    @Thunk Launcher mLauncher;
     private Handler mHandler;
 
     // temporaries to avoid gc thrash
@@ -102,17 +104,17 @@
 
     private View mMoveTarget;
 
-    private DragScroller mDragScroller;
-    private int mScrollState = SCROLL_OUTSIDE_ZONE;
+    @Thunk DragScroller mDragScroller;
+    @Thunk int mScrollState = SCROLL_OUTSIDE_ZONE;
     private ScrollRunnable mScrollRunnable = new ScrollRunnable();
 
     private DropTarget mLastDropTarget;
 
     private InputMethodManager mInputMethodManager;
 
-    private int mLastTouch[] = new int[2];
-    private long mLastTouchUpTime = -1;
-    private int mDistanceSinceScroll = 0;
+    @Thunk int mLastTouch[] = new int[2];
+    @Thunk long mLastTouchUpTime = -1;
+    @Thunk int mDistanceSinceScroll = 0;
 
     private int mTmpPoint[] = new int[2];
     private Rect mDragLayerRect = new Rect();
@@ -543,7 +545,7 @@
         mLastDropTarget = dropTarget;
     }
 
-    private void checkScrollState(int x, int y) {
+    @Thunk void checkScrollState(int x, int y) {
         final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
         final int delay = mDistanceSinceScroll < slop ? RESCROLL_DELAY : SCROLL_DELAY;
         final DragLayer dragLayer = mLauncher.getDragLayer();
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index a352b79..ab2e094 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -39,6 +39,7 @@
 import android.widget.TextView;
 
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
@@ -46,7 +47,7 @@
  * A ViewGroup that coordinates dragging across its descendants
  */
 public class DragLayer extends InsettableFrameLayout {
-    private DragController mDragController;
+    @Thunk DragController mDragController;
     private int[] mTmpXY = new int[2];
 
     private int mXDown, mYDown;
@@ -61,9 +62,9 @@
     private ValueAnimator mDropAnim = null;
     private ValueAnimator mFadeOutAnim = null;
     private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
-    private DragView mDropView = null;
-    private int mAnchorViewInitialScrollX = 0;
-    private View mAnchorView = null;
+    @Thunk DragView mDropView = null;
+    @Thunk int mAnchorViewInitialScrollX = 0;
+    @Thunk View mAnchorView = null;
 
     private boolean mHoverPointClosesFolder = false;
     private Rect mHitRect = new Rect();
@@ -779,7 +780,7 @@
         return mDropView;
     }
 
-    private void fadeOutDragView() {
+    @Thunk void fadeOutDragView() {
         mFadeOutAnim = new ValueAnimator();
         mFadeOutAnim.setDuration(150);
         mFadeOutAnim.setFloatValues(0f, 1f);
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index 78d72b3..b1a6266 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -29,8 +29,10 @@
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher3.util.Thunk;
+
 public class DragView extends View {
-    private static float sDragAlpha = 1f;
+    @Thunk static float sDragAlpha = 1f;
 
     private Bitmap mBitmap;
     private Bitmap mCrossFadeBitmap;
@@ -42,11 +44,11 @@
     private Rect mDragRegion = null;
     private DragLayer mDragLayer = null;
     private boolean mHasDrawn = false;
-    private float mCrossFadeProgress = 0f;
+    @Thunk float mCrossFadeProgress = 0f;
 
     ValueAnimator mAnim;
-    private float mOffsetX = 0.0f;
-    private float mOffsetY = 0.0f;
+    @Thunk float mOffsetX = 0.0f;
+    @Thunk float mOffsetY = 0.0f;
     private float mInitialScale = 1f;
     // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
     // size.  This is ignored for non-icons.
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index 095c563..a51ddd4 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -24,6 +24,8 @@
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 
+import com.android.launcher3.util.Thunk;
+
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
  *  For the first two frames, it adjusts the current play time of the animation to
@@ -41,7 +43,7 @@
     private boolean mAdjustedSecondFrameTime;
 
     private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
-    private static long sGlobalFrameCounter;
+    @Thunk static long sGlobalFrameCounter;
     private static boolean sVisible;
 
     public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index fc68952..327fac4 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -25,6 +25,7 @@
 
 import com.android.launcher3.FocusHelper.PagedViewKeyListener;
 import com.android.launcher3.util.FocusLogic;
+import com.android.launcher3.util.Thunk;
 
 /**
  * A keyboard listener we set on all the workspace icons.
@@ -480,7 +481,7 @@
     /**
      * Returns the Viewgroup containing page contents for the page at the index specified.
      */
-    private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
+    @Thunk static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
         ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index);
         if (page instanceof CellLayout) {
             // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
@@ -510,7 +511,7 @@
     /**
      * Helper method to be used for playing sound effects.
      */
-    private static void playSoundEffect(int keyCode, View v) {
+    @Thunk static void playSoundEffect(int keyCode, View v) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_LEFT:
                 v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
index af3b976..ab21c90 100644
--- a/src/com/android/launcher3/FocusIndicatorView.java
+++ b/src/com/android/launcher3/FocusIndicatorView.java
@@ -24,6 +24,8 @@
 import android.util.Pair;
 import android.view.View;
 
+import com.android.launcher3.util.Thunk;
+
 public class FocusIndicatorView extends View implements View.OnFocusChangeListener {
 
     // It can be any number >0. The view is resized using scaleX and scaleY.
@@ -176,7 +178,7 @@
         }
     }
 
-    private static final class ViewAnimState {
+    @Thunk static final class ViewAnimState {
         float x, y, scaleX, scaleY;
     }
 }
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 5d8a865..23582ce 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -51,6 +51,7 @@
 
 import com.android.launcher3.FolderInfo.FolderListener;
 import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -106,7 +107,7 @@
     private final Alarm mReorderAlarm = new Alarm();
     private final Alarm mOnExitAlarm = new Alarm();
 
-    private final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
+    @Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
 
     private final int mExpandDuration;
     private final int mMaterialExpandDuration;
@@ -118,19 +119,19 @@
     protected DragController mDragController;
     protected FolderInfo mInfo;
 
-    private FolderIcon mFolderIcon;
+    @Thunk FolderIcon mFolderIcon;
 
-    private FolderContent mContent;
-    private View mContentWrapper;
+    @Thunk FolderContent mContent;
+    @Thunk View mContentWrapper;
     FolderEditText mFolderName;
 
     private View mFooter;
     private int mFooterHeight;
 
     // Cell ranks used for drag and drop
-    private int mTargetRank, mPrevTargetRank, mEmptyCellRank;
+    @Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
 
-    private int mState = STATE_NONE;
+    @Thunk int mState = STATE_NONE;
     private boolean mRearrangeOnClose = false;
     boolean mItemsInvalidated = false;
     private ShortcutInfo mCurrentDragInfo;
@@ -141,26 +142,26 @@
     private boolean mDeleteFolderOnDropCompleted = false;
     private boolean mSuppressFolderDeletion = false;
     private boolean mItemAddedBackToSelfViaIcon = false;
-    private float mFolderIconPivotX;
-    private float mFolderIconPivotY;
+    @Thunk float mFolderIconPivotX;
+    @Thunk float mFolderIconPivotY;
     private boolean mIsEditingName = false;
 
     private boolean mDestroyed;
 
-    private Runnable mDeferredAction;
+    @Thunk Runnable mDeferredAction;
     private boolean mDeferDropAfterUninstall;
     private boolean mUninstallSuccessful;
 
     // Folder scrolling
     private int mScrollAreaOffset;
     private Alarm mOnScrollHintAlarm;
-    private Alarm mScrollPauseAlarm;
+    @Thunk Alarm mScrollPauseAlarm;
 
     // TODO: Use {@link #mContent} once {@link #ALLOW_FOLDER_SCROLL} is removed.
-    private FolderPagedView mPagedView;
+    @Thunk FolderPagedView mPagedView;
 
-    private int mScrollHintDir = DragController.SCROLL_NONE;
-    private int mCurrentScrollDir = DragController.SCROLL_NONE;
+    @Thunk int mScrollHintDir = DragController.SCROLL_NONE;
+    @Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
 
     /**
      * Used to inflate the Workspace from XML.
@@ -556,7 +557,7 @@
 
     }
 
-    private void sendCustomAccessibilityEvent(int type, String text) {
+    @Thunk void sendCustomAccessibilityEvent(int type, String text) {
         AccessibilityManager accessibilityManager = (AccessibilityManager)
                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
         if (accessibilityManager.isEnabled()) {
@@ -635,7 +636,7 @@
                 (int) recycle[0] - getPaddingLeft(), (int) recycle[1] - getPaddingTop());
     }
 
-    private void onDragOver(DragObject d, int reorderDelay) {
+    @Thunk void onDragOver(DragObject d, int reorderDelay) {
         if (ALLOW_FOLDER_SCROLL && mScrollPauseAlarm.alarmPending()) {
             return;
         }
@@ -997,7 +998,7 @@
         return mContent.getItemCount();
     }
 
-    private void onCloseComplete() {
+    @Thunk void onCloseComplete() {
         DragLayer parent = (DragLayer) getParent();
         if (parent != null) {
             parent.removeView(this);
@@ -1020,7 +1021,7 @@
         mSuppressFolderDeletion = false;
     }
 
-    private void replaceFolderWithFinalItem() {
+    @Thunk void replaceFolderWithFinalItem() {
         // Add the last remaining child to the workspace in place of the folder
         Runnable onCompleteRunnable = new Runnable() {
             @Override
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index dbfedaa..f5836c2 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -43,6 +43,7 @@
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.FolderInfo.FolderListener;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
@@ -50,10 +51,10 @@
  * An icon that can appear on in the workspace representing an {@link UserFolder}.
  */
 public class FolderIcon extends FrameLayout implements FolderListener {
-    private Launcher mLauncher;
-    private Folder mFolder;
+    @Thunk Launcher mLauncher;
+    @Thunk Folder mFolder;
     private FolderInfo mInfo;
-    private static boolean sStaticValuesDirty = true;
+    @Thunk static boolean sStaticValuesDirty = true;
 
     private CheckLongPressHelper mLongPressHelper;
 
@@ -88,8 +89,8 @@
 
     public static Drawable sSharedFolderLeaveBehind = null;
 
-    private ImageView mPreviewBackground;
-    private BubbleTextView mFolderName;
+    @Thunk ImageView mPreviewBackground;
+    @Thunk BubbleTextView mFolderName;
 
     FolderRingAnimator mFolderRingAnimator = null;
 
@@ -109,11 +110,11 @@
     private float mSlop;
 
     private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-    private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-    private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
+    @Thunk PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+    @Thunk ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
 
     private Alarm mOpenAlarm = new Alarm();
-    private ItemInfo mDragInfo;
+    @Thunk ItemInfo mDragInfo;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -192,7 +193,7 @@
     public static class FolderRingAnimator {
         public int mCellX;
         public int mCellY;
-        private CellLayout mCellLayout;
+        @Thunk CellLayout mCellLayout;
         public float mOuterRingSize;
         public float mInnerRingSize;
         public FolderIcon mFolderIcon = null;
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 21158b4..9f3126c 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -31,6 +31,7 @@
 import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
 import com.android.launcher3.PageIndicator.PageMarkerResources;
 import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.util.Thunk;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -59,7 +60,8 @@
 
     private final LayoutInflater mInflater;
     private final IconCache mIconCache;
-    private final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
+
+    @Thunk final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
 
     private final int mMaxCountX;
     private final int mMaxCountY;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 39a80be..3c7adbe 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Thunk;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -66,7 +67,7 @@
 
     private static final int LOW_RES_SCALE_FACTOR = 8;
 
-    private static class CacheEntry {
+    @Thunk static class CacheEntry {
         public Bitmap icon;
         public CharSequence title;
         public CharSequence contentDescription;
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 201531e..4349e16 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -240,7 +241,7 @@
      * Ensures that we have a valid, non-null name.  If the provided name is null, we will return
      * the application name instead.
      */
-    private static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
+    @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
         if (name == null) {
             try {
                 PackageManager pm = context.getPackageManager();
diff --git a/src/com/android/launcher3/InterruptibleInOutAnimator.java b/src/com/android/launcher3/InterruptibleInOutAnimator.java
index 2898b34..29df38b 100644
--- a/src/com/android/launcher3/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher3/InterruptibleInOutAnimator.java
@@ -21,6 +21,8 @@
 import android.animation.ValueAnimator;
 import android.view.View;
 
+import com.android.launcher3.util.Thunk;
+
 /**
  * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
  * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
@@ -43,7 +45,7 @@
     private static final int OUT = 2;
 
     // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
-    private int mDirection = STOPPED;
+    @Thunk int mDirection = STOPPED;
 
     public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
         mAnimator = LauncherAnimUtils.ofFloat(view, fromValue, toValue).setDuration(duration);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d64296e..f2610d6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -101,6 +101,7 @@
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -209,9 +210,9 @@
 
     /** The different states that Launcher can be in. */
     enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED };
-    private State mState = State.WORKSPACE;
-    private AnimatorSet mStateAnimation;
-    private LauncherStateTransitionAnimation mStateTransitionAnimation;
+    @Thunk State mState = State.WORKSPACE;
+    @Thunk AnimatorSet mStateAnimation;
+    @Thunk LauncherStateTransitionAnimation mStateTransitionAnimation;
 
     private boolean mIsSafeModeEnabled;
 
@@ -230,7 +231,7 @@
     // How long to wait before the new-shortcut animation automatically pans the workspace
     private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
-    private static int NEW_APPS_ANIMATION_DELAY = 500;
+    @Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
 
     private final BroadcastReceiver mCloseSystemDialogsReceiver
             = new CloseSystemDialogsIntentReceiver();
@@ -238,17 +239,17 @@
 
     private LayoutInflater mInflater;
 
-    private Workspace mWorkspace;
+    @Thunk Workspace mWorkspace;
     private View mLauncherView;
     private View mPageIndicators;
-    private DragLayer mDragLayer;
+    @Thunk DragLayer mDragLayer;
     private DragController mDragController;
     private View mWeightWatcher;
 
     private AppWidgetManagerCompat mAppWidgetManager;
     private LauncherAppWidgetHost mAppWidgetHost;
 
-    private ItemInfo mPendingAddInfo = new ItemInfo();
+    @Thunk ItemInfo mPendingAddInfo = new ItemInfo();
     private LauncherAppWidgetProviderInfo mPendingAddWidgetInfo;
     private int mPendingAddWidgetId = -1;
 
@@ -262,8 +263,8 @@
     private View mAllAppsButton;
 
     private SearchDropTargetBar mSearchDropTargetBar;
-    private AppsContainerView mAppsView;
-    private AppsCustomizeTabHost mAppsCustomizeTabHost;
+    @Thunk AppsContainerView mAppsView;
+    @Thunk AppsCustomizeTabHost mAppsCustomizeTabHost;
     private AppsCustomizePagedView mAppsCustomizeContent;
     private boolean mAutoAdvanceRunning = false;
     private AppWidgetHostView mQsb;
@@ -276,7 +277,7 @@
 
     private SpannableStringBuilder mDefaultKeySsb = null;
 
-    private boolean mWorkspaceLoading = true;
+    @Thunk boolean mWorkspaceLoading = true;
 
     private boolean mPaused = true;
     private boolean mRestoring;
@@ -290,12 +291,12 @@
 
     private LauncherModel mModel;
     private IconCache mIconCache;
-    private boolean mUserPresent = true;
+    @Thunk boolean mUserPresent = true;
     private boolean mVisible = false;
     private boolean mHasFocus = false;
     private boolean mAttached = false;
 
-    private static LocaleConfiguration sLocaleConfiguration = null;
+    @Thunk static LocaleConfiguration sLocaleConfiguration = null;
 
     private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
 
@@ -307,14 +308,14 @@
     private final int mAdvanceStagger = 250;
     private long mAutoAdvanceSentTime;
     private long mAutoAdvanceTimeLeft = -1;
-    private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
+    @Thunk HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
         new HashMap<View, AppWidgetProviderInfo>();
 
     // Determines how long to wait after a rotation before restoring the screen orientation to
     // match the sensor state.
     private final int mRestoreScreenOrientationDelay = 500;
 
-    private Drawable mWorkspaceBackgroundDrawable;
+    @Thunk Drawable mWorkspaceBackgroundDrawable;
 
     private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
     private static final boolean DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE = false;
@@ -332,7 +333,7 @@
 
     // Holds the page that we need to animate to, and the icon views that we need to animate up
     // when we scroll to that page on resume.
-    private ImageView mFolderIconImageView;
+    @Thunk ImageView mFolderIconImageView;
     private Bitmap mFolderIconBitmap;
     private Canvas mFolderIconCanvas;
     private Rect mRectForFolderAnimation = new Rect();
@@ -361,7 +362,7 @@
         }
     }
 
-    private Runnable mBuildLayersRunnable = new Runnable() {
+    @Thunk Runnable mBuildLayersRunnable = new Runnable() {
         public void run() {
             if (mWorkspace != null) {
                 mWorkspace.buildPageHardwareLayers();
@@ -371,7 +372,7 @@
 
     private static PendingAddArguments sPendingAddItem;
 
-    private static class PendingAddArguments {
+    @Thunk static class PendingAddArguments {
         int requestCode;
         Intent intent;
         long container;
@@ -560,7 +561,7 @@
         }
     }
 
-    private void checkForLocaleChange() {
+    @Thunk void checkForLocaleChange() {
         if (sLocaleConfiguration == null) {
             new AsyncTask<Void, Void, LocaleConfiguration>() {
                 @Override
@@ -609,13 +610,13 @@
         }
     }
 
-    private static class LocaleConfiguration {
+    @Thunk static class LocaleConfiguration {
         public String locale;
         public int mcc = -1;
         public int mnc = -1;
     }
 
-    private static void readConfiguration(Context context, LocaleConfiguration configuration) {
+    @Thunk static void readConfiguration(Context context, LocaleConfiguration configuration) {
         DataInputStream in = null;
         try {
             in = new DataInputStream(context.openFileInput(LauncherFiles.LAUNCHER_PREFERENCES));
@@ -637,7 +638,7 @@
         }
     }
 
-    private static void writeConfiguration(Context context, LocaleConfiguration configuration) {
+    @Thunk static void writeConfiguration(Context context, LocaleConfiguration configuration) {
         DataOutputStream out = null;
         try {
             out = new DataOutputStream(context.openFileOutput(
@@ -914,7 +915,7 @@
         }
     }
 
-    private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
+    @Thunk void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
         CellLayout cellLayout =
                 (CellLayout) mWorkspace.getScreenWithId(mPendingAddInfo.screenId);
         Runnable onCompleteRunnable = null;
@@ -1590,7 +1591,7 @@
      *
      * @param appWidgetId The app widget id
      */
-    private void completeAddAppWidget(int appWidgetId, long container, long screenId,
+    @Thunk void completeAddAppWidget(int appWidgetId, long container, long screenId,
             AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
 
         ItemInfo info = mPendingAddInfo;
@@ -1765,14 +1766,14 @@
         }
     }
 
-    private void sendAdvanceMessage(long delay) {
+    @Thunk void sendAdvanceMessage(long delay) {
         mHandler.removeMessages(ADVANCE_MSG);
         Message msg = mHandler.obtainMessage(ADVANCE_MSG);
         mHandler.sendMessageDelayed(msg, delay);
         mAutoAdvanceSentTime = System.currentTimeMillis();
     }
 
-    private void updateAutoAdvanceState() {
+    @Thunk void updateAutoAdvanceState() {
         boolean autoAdvanceRunning = mVisible && mUserPresent && !mWidgetsToAdvance.isEmpty();
         if (autoAdvanceRunning != mAutoAdvanceRunning) {
             mAutoAdvanceRunning = autoAdvanceRunning;
@@ -2482,7 +2483,7 @@
     /**
      * Re-listen when widgets are reset.
      */
-    private void onAppWidgetReset() {
+    @Thunk void onAppWidgetReset() {
         if (mAppWidgetHost != null) {
             mAppWidgetHost.startListening();
         }
@@ -2680,7 +2681,7 @@
         }
     }
 
-    private void startAppShortcutOrInfoActivity(View v) {
+    @Thunk void startAppShortcutOrInfoActivity(View v) {
         Object tag = v.getTag();
         final ShortcutInfo shortcut;
         final Intent intent;
@@ -3507,7 +3508,7 @@
     /**
      * Receives notifications when system dialogs are to be closed.
      */
-    private class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
+    @Thunk class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             closeSystemDialogs();
@@ -3872,7 +3873,7 @@
         final Workspace workspace = mWorkspace;
 
         LauncherAppWidgetProviderInfo appWidgetInfo =
-                LauncherModel.getProviderInfo(this, item.providerName);
+                LauncherModel.getProviderInfo(this, item.providerName, item.user);
 
         if (!mIsSafeModeEnabled
                 && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
@@ -4245,7 +4246,7 @@
     /**
      * A number of packages were updated.
      */
-    private ArrayList<Object> mWidgetsAndShortcuts;
+    @Thunk ArrayList<Object> mWidgetsAndShortcuts;
     private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
             public void run() {
                 bindPackagesUpdated(mWidgetsAndShortcuts);
@@ -4470,7 +4471,7 @@
         editor.apply();
     }
 
-    private void showFirstRunClings() {
+    @Thunk void showFirstRunClings() {
         // The two first run cling paths are mutually exclusive, if the launcher is preinstalled
         // on the device, then we always show the first run cling experience (or if there is no
         // launcher2). Otherwise, we prompt the user upon started for migration
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index 0ae1c0e..42f1914 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -15,6 +15,7 @@
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import com.android.launcher3.LauncherModel.ScreenPosProvider;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
@@ -43,7 +44,7 @@
 
     private final SparseArray<AccessibilityAction> mActions =
             new SparseArray<AccessibilityAction>();
-    private final Launcher mLauncher;
+    @Thunk final Launcher mLauncher;
 
     public LauncherAccessibilityDelegate(Launcher launcher) {
         mLauncher = launcher;
@@ -139,11 +140,11 @@
         return false;
     }
 
-    private void announceConfirmation(int resId) {
+    @Thunk void announceConfirmation(int resId) {
         announceConfirmation(mLauncher.getResources().getString(resId));
     }
 
-    private void announceConfirmation(String confirmation) {
+    @Thunk void announceConfirmation(String confirmation) {
         mLauncher.getDragLayer().announceForAccessibility(confirmation);
 
     }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 8c6fc60..9082276 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -38,6 +38,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
+import com.android.launcher3.util.Thunk;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -46,7 +47,7 @@
 
     private final AppFilter mAppFilter;
     private final BuildInfo mBuildInfo;
-    private final LauncherModel mModel;
+    @Thunk final LauncherModel mModel;
     private final IconCache mIconCache;
 
     private final boolean mIsScreenLarge;
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 97ff327..57f92bc 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -631,7 +631,6 @@
         }
         final ContentResolver cr = mContext.getContentResolver();
         final WidgetPreviewLoader previewLoader = new WidgetPreviewLoader(mContext);
-        final PagedViewCellLayout widgetSpacingLayout = new PagedViewCellLayout(mContext);
         final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
         final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile();
         if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx);
@@ -666,9 +665,13 @@
                     if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount);
                     if (backupWidgetCount < MAX_WIDGETS_PER_PASS) {
                         if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
-                        previewLoader.setPreviewSize(spanX * profile.cellWidthPx,
-                                spanY * profile.cellHeightPx, widgetSpacingLayout);
-                        writeRowToBackup(key, packWidget(dpi, previewLoader, mIconCache, provider), data);
+                        previewLoader.setPreviewSize(
+                                spanX * profile.cellWidthPx,
+                                spanY * profile.cellHeightPx);
+                        UserHandleCompat user = UserHandleCompat.myUserHandle();
+                        writeRowToBackup(key,
+                                packWidget(dpi, previewLoader, mIconCache, provider, user),
+                                data);
                         mKeys.add(key);
                         backupWidgetCount ++;
                     } else {
@@ -978,9 +981,9 @@
 
     /** Serialize a widget for persistence, including a checksum wrapper. */
     private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache,
-            ComponentName provider) {
+            ComponentName provider, UserHandleCompat user) {
         final LauncherAppWidgetProviderInfo info =
-                LauncherModel.getProviderInfo(mContext, provider);
+                LauncherModel.getProviderInfo(mContext, provider, user);
         Widget widget = new Widget();
         widget.provider = provider.flattenToShortString();
         widget.label = info.label;
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
index ef8e8ab..2ce8b1c 100644
--- a/src/com/android/launcher3/LauncherClings.java
+++ b/src/com/android/launcher3/LauncherClings.java
@@ -35,6 +35,8 @@
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.launcher3.util.Thunk;
+
 class LauncherClings implements OnClickListener {
     private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed";
     private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
@@ -49,7 +51,7 @@
     // New Secure Setting in L
     private static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
 
-    private Launcher mLauncher;
+    @Thunk Launcher mLauncher;
     private LayoutInflater mInflater;
 
     /** Ctor */
@@ -174,7 +176,7 @@
         });
     }
 
-    private void dismissLongPressCling() {
+    @Thunk void dismissLongPressCling() {
         Runnable dismissCb = new Runnable() {
             public void run() {
                 dismissCling(mLauncher.findViewById(R.id.longpress_cling), null,
@@ -185,7 +187,7 @@
     }
 
     /** Hides the specified Cling */
-    private void dismissCling(final View cling, final Runnable postAnimationCb,
+    @Thunk void dismissCling(final View cling, final Runnable postAnimationCb,
                               final String flag, int duration) {
         // To catch cases where siblings of top-level views are made invisible, just check whether
         // the cling is directly set to GONE before dismissing it.
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index cedb397..ce277c1 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -18,9 +18,7 @@
     public static final String DEFAULT_WALLPAPER_THUMBNAIL_OLD = "default_thumb.jpg";
     public static final String LAUNCHER_DB = "launcher.db";
     public static final String LAUNCHER_PREFERENCES = "launcher.preferences";
-    public static final String LAUNCHES_LOG = "launches.log";
     public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
-    public static final String STATS_LOG = "stats.log";
     public static final String WALLPAPER_CROP_PREFERENCES_KEY =
             WallpaperCropActivity.class.getName();
     public static final String WALLPAPER_IMAGES_DB = "saved_wallpaper_images.db";
@@ -32,11 +30,14 @@
             DEFAULT_WALLPAPER_THUMBNAIL_OLD,
             LAUNCHER_DB,
             LAUNCHER_PREFERENCES,
-            LAUNCHES_LOG,
             SHARED_PREFERENCES_KEY + XML,
-            STATS_LOG,
             WALLPAPER_CROP_PREFERENCES_KEY + XML,
             WALLPAPER_IMAGES_DB,
             WIDGET_PREVIEWS_DB,
             APP_ICONS_DB));
+
+    // TODO: Delete these files on upgrade
+    public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
+            "launches.log",
+            "stats.log"));
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 1e16baf..8cedcc5 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -58,6 +58,8 @@
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Thunk;
 
 import java.lang.ref.WeakReference;
 import java.net.URISyntaxException;
@@ -96,14 +98,14 @@
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
     private static final long INVALID_SCREEN_ID = -1L;
 
-    private final boolean mAppsCanBeOnRemoveableStorage;
+    @Thunk final boolean mAppsCanBeOnRemoveableStorage;
     private final boolean mOldContentProviderExists;
 
-    private final LauncherAppState mApp;
-    private final Object mLock = new Object();
-    private DeferredHandler mHandler = new DeferredHandler();
-    private LoaderTask mLoaderTask;
-    private boolean mIsLoaderTaskRunning;
+    @Thunk final LauncherAppState mApp;
+    @Thunk final Object mLock = new Object();
+    @Thunk DeferredHandler mHandler = new DeferredHandler();
+    @Thunk LoaderTask mLoaderTask;
+    @Thunk boolean mIsLoaderTaskRunning;
 
     /**
      * Maintain a set of packages per user, for which we added a shortcut on the workspace.
@@ -117,17 +119,17 @@
 
     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
 
-    static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
+    @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
     static {
         sWorkerThread.start();
     }
-    private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
+    @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
 
     // We start off with everything not loaded.  After that, we assume that
     // our monitoring of the package manager provides all updates and we never
     // need to do a requery.  These are only ever touched from the loader thread.
-    private boolean mWorkspaceLoaded;
-    private boolean mAllAppsLoaded;
+    @Thunk boolean mWorkspaceLoaded;
+    @Thunk boolean mAllAppsLoaded;
 
     // When we are loading pages synchronously, we can't just post the binding of items on the side
     // pages as this delays the rotation process.  Instead, we wait for a callback from the first
@@ -135,7 +137,7 @@
     // a normal load, we also clear this set of Runnables.
     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();
 
-    private WeakReference<Callbacks> mCallbacks;
+    @Thunk WeakReference<Callbacks> mCallbacks;
 
     // < only access in worker thread >
     AllAppsList mBgAllAppsList;
@@ -166,7 +168,7 @@
     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
 
     // sBgWidgetProviders is the set of widget providers including custom internal widgets
-    public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;
+    public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;
 
     // sPendingPackages is a set of packages which could be on sdcard and are not available yet
     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
@@ -174,12 +176,12 @@
 
     // </ only access in worker thread >
 
-    private IconCache mIconCache;
+    @Thunk IconCache mIconCache;
 
     protected int mPreviousConfigMcc;
 
-    private final LauncherAppsCompat mLauncherApps;
-    private final UserManagerCompat mUserManager;
+    @Thunk final LauncherAppsCompat mLauncherApps;
+    @Thunk final UserManagerCompat mUserManager;
 
     public interface Callbacks {
         public boolean setLoadOnResume();
@@ -257,10 +259,10 @@
 
     /** Runs the specified runnable immediately if called from the main thread, otherwise it is
      * posted on the main thread handler. */
-    private void runOnMainThread(Runnable r) {
+    @Thunk void runOnMainThread(Runnable r) {
         runOnMainThread(r, 0);
     }
-    private void runOnMainThread(Runnable r, int type) {
+    @Thunk void runOnMainThread(Runnable r, int type) {
         if (sWorkerThread.getThreadId() == Process.myTid()) {
             // If we are on the worker thread, post onto the main handler
             mHandler.post(r);
@@ -371,7 +373,7 @@
      * Find a position on the screen for the given size or adds a new screen.
      * @return screenId and the coordinates for the item.
      */
-    private static Pair<Long, int[]> findSpaceForItem(
+    @Thunk static Pair<Long, int[]> findSpaceForItem(
             Context context,
             ScreenPosProvider preferredScreen,
             int fallbackStartScreen,
@@ -1424,7 +1426,7 @@
     /**
      * Loads the workspace screen ids in an ordered list.
      */
-    private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
+    @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
         final ContentResolver contentResolver = context.getContentResolver();
         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
 
@@ -1470,9 +1472,9 @@
     private class LoaderTask implements Runnable {
         private Context mContext;
         private boolean mIsLaunching;
-        private boolean mIsLoadingAndBindingWorkspace;
+        @Thunk boolean mIsLoadingAndBindingWorkspace;
         private boolean mStopped;
-        private boolean mLoadAndBindStepFinished;
+        @Thunk boolean mLoadAndBindStepFinished;
         private int mFlags;
 
         LoaderTask(Context context, boolean isLaunching, int flags) {
@@ -1872,6 +1874,7 @@
                     LauncherAppWidgetInfo appWidgetInfo;
                     int container;
                     long id;
+                    long serialNumber;
                     Intent intent;
                     UserHandleCompat user;
 
@@ -1886,7 +1889,7 @@
                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                                 id = c.getLong(idIndex);
                                 intentDescription = c.getString(intentIndex);
-                                long serialNumber = c.getInt(profileIdIndex);
+                                serialNumber = c.getInt(profileIdIndex);
                                 user = mUserManager.getUserForSerialNumber(serialNumber);
                                 int promiseType = c.getInt(restoredIndex);
                                 int disabledState = 0;
@@ -2150,6 +2153,7 @@
                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
 
                                 int appWidgetId = c.getInt(appWidgetIdIndex);
+                                serialNumber= c.getLong(profileIdIndex);
                                 String savedProvider = c.getString(appWidgetProviderIndex);
                                 id = c.getLong(idIndex);
                                 final ComponentName component =
@@ -2164,7 +2168,8 @@
 
                                 final LauncherAppWidgetProviderInfo provider =
                                         LauncherModel.getProviderInfo(context,
-                                                ComponentName.unflattenFromString(savedProvider));
+                                                ComponentName.unflattenFromString(savedProvider),
+                                                mUserManager.getUserForSerialNumber(serialNumber));
 
                                 final boolean isProviderReady = isValidProvider(provider);
                                 if (!isSafeMode && !customWidget &&
@@ -2900,7 +2905,7 @@
         sWorker.post(task);
     }
 
-    private class AppsAvailabilityCheck extends BroadcastReceiver {
+    @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -3283,33 +3288,36 @@
     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,
             boolean refresh) {
         synchronized (sBgLock) {
-            if (sBgWidgetProviders != null && !refresh) {
-                return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());
-            }
-            sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();
-            List<AppWidgetProviderInfo> widgets =
-                    AppWidgetManagerCompat.getInstance(context).getAllProviders();
-            LauncherAppWidgetProviderInfo info;
-            for (AppWidgetProviderInfo pInfo : widgets) {
-                info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
-                sBgWidgetProviders.put(info.provider, info);
-            }
+            if (sBgWidgetProviders == null || refresh) {
+                sBgWidgetProviders = new HashMap<>();
+                AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);
+                LauncherAppWidgetProviderInfo info;
 
-            Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
-            for (CustomAppWidget widget : customWidgets) {
-                info = new LauncherAppWidgetProviderInfo(context, widget);
-                sBgWidgetProviders.put(info.provider, info);
+                List<AppWidgetProviderInfo> widgets = wm.getAllProviders();
+                for (AppWidgetProviderInfo pInfo : widgets) {
+                    info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
+                    UserHandleCompat user = wm.getUser(info);
+                    sBgWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                }
+
+                Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
+                for (CustomAppWidget widget : customWidgets) {
+                    info = new LauncherAppWidgetProviderInfo(context, widget);
+                    UserHandleCompat user = wm.getUser(info);
+                    sBgWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                }
             }
             return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());
         }
     }
 
-    public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {
+    public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,
+            UserHandleCompat user) {
         synchronized (sBgLock) {
             if (sBgWidgetProviders == null) {
                 getWidgetProviders(ctx, false /* refresh */);
             }
-            return sBgWidgetProviders.get(name);
+            return sBgWidgetProviders.get(new ComponentKey(name, user));
         }
     }
 
@@ -3324,7 +3332,7 @@
         return widgetsAndShortcuts;
     }
 
-    private static boolean isPackageDisabled(Context context, String packageName,
+    @Thunk static boolean isPackageDisabled(Context context, String packageName,
             UserHandleCompat user) {
         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
         return !launcherApps.isPackageEnabledForProfile(packageName, user);
@@ -3387,7 +3395,7 @@
      * Make an Intent object for a restored application or shortcut item that points
      * to the market page for the item.
      */
-    private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
+    @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
         ComponentName componentName = intent.getComponent();
         return getMarketIntent(componentName.getPackageName());
     }
@@ -3482,7 +3490,7 @@
         return new ArrayList<ItemInfo>(filtered);
     }
 
-    private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
+    @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
             final UserHandleCompat user) {
         ItemInfoFilter filter  = new ItemInfoFilter() {
             @Override
@@ -3500,7 +3508,7 @@
     /**
      * Make an ShortcutInfo object for a shortcut that isn't an application.
      */
-    private ShortcutInfo getShortcutInfo(Cursor c, Context context,
+    @Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,
             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,
             int titleIndex) {
 
@@ -3604,7 +3612,7 @@
      * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
+    @Thunk static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
         // See if a placeholder was created for us already
         FolderInfo folderInfo = folders.get(id);
         if (folderInfo == null) {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 59c8d92..6dd1305 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.util.Thunk;
 
 import java.io.File;
 import java.net.URISyntaxException;
@@ -124,7 +125,7 @@
         return result;
     }
 
-    private static long dbInsertAndCheck(DatabaseHelper helper,
+    @Thunk static long dbInsertAndCheck(DatabaseHelper helper,
             SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
         if (values == null) {
             throw new RuntimeException("Error: attempting to insert null values");
@@ -233,7 +234,7 @@
         }
     }
 
-    private static void addModifiedTime(ContentValues values) {
+    @Thunk static void addModifiedTime(ContentValues values) {
         values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis());
     }
 
@@ -342,7 +343,7 @@
 
     private static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
         private final Context mContext;
-        private final AppWidgetHost mAppWidgetHost;
+        @Thunk final AppWidgetHost mAppWidgetHost;
         private long mMaxItemId = -1;
         private long mMaxScreenId = -1;
 
@@ -647,7 +648,7 @@
             return true;
         }
 
-        private boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
+        @Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
             db.beginTransaction();
             try {
                 if (addRankColumn) {
@@ -758,7 +759,7 @@
             return getMaxId(db, TABLE_WORKSPACE_SCREENS);
         }
 
-        private boolean initializeExternalAdd(ContentValues values) {
+        @Thunk boolean initializeExternalAdd(ContentValues values) {
             // 1. Ensure that externally added items have a valid item id
             long id = generateNewItemId();
             values.put(LauncherSettings.Favorites._ID, id);
@@ -845,7 +846,7 @@
             return rank;
         }
 
-        private int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
+        @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
             ArrayList<Long> screenIds = new ArrayList<Long>();
             // TODO: Use multiple loaders with fall-back and transaction.
             int count = loader.loadLayout(db, screenIds);
@@ -872,7 +873,7 @@
             return count;
         }
 
-        private void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
+        @Thunk void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
             final ContentResolver resolver = mContext.getContentResolver();
             Cursor c = null;
             int count = 0;
@@ -1171,7 +1172,7 @@
     /**
      * @return the max _id in the provided table.
      */
-    private static long getMaxId(SQLiteDatabase db, String table) {
+    @Thunk static long getMaxId(SQLiteDatabase db, String table) {
         Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null);
         // get the result
         long id = -1;
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 484ed5c3..4a0aaf3 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -29,6 +29,8 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.HashMap;
 
 /**
@@ -112,9 +114,9 @@
     public static final int BUILD_AND_SET_LAYER = 1;
     public static final int SINGLE_FRAME_DELAY = 16;
 
-    private Launcher mLauncher;
-    private Callbacks mCb;
-    private AnimatorSet mStateAnimation;
+    @Thunk Launcher mLauncher;
+    @Thunk Callbacks mCb;
+    @Thunk AnimatorSet mStateAnimation;
 
     public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
         mLauncher = l;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 7d65f46..e7049e2 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -51,6 +51,8 @@
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 
 interface Page {
@@ -124,7 +126,7 @@
     protected LauncherScroller mScroller;
     private Interpolator mDefaultInterpolator;
     private VelocityTracker mVelocityTracker;
-    private int mPageSpacing = 0;
+    @Thunk int mPageSpacing = 0;
 
     private float mParentDownMotionX;
     private float mParentDownMotionY;
@@ -207,8 +209,8 @@
     private boolean mWasInOverscroll = false;
 
     // Page Indicator
-    private int mPageIndicatorViewId;
-    private PageIndicator mPageIndicator;
+    @Thunk int mPageIndicatorViewId;
+    @Thunk PageIndicator mPageIndicator;
     private boolean mAllowPagedViewAnimations = true;
 
     // The viewport whether the pages are to be contained (the actual view may be larger than the
@@ -227,7 +229,7 @@
     protected View mDragView;
     protected AnimatorSet mZoomInOutAnim;
     private Runnable mSidePageHoverRunnable;
-    private int mSidePageHoverIndex = -1;
+    @Thunk int mSidePageHoverIndex = -1;
     // This variable's scope is only for the duration of startReordering() and endReordering()
     private boolean mReorderingStarted = false;
     // This variable's scope is for the duration of startReordering() and after the zoomIn()
@@ -246,14 +248,14 @@
     private Rect mAltTmpRect = new Rect();
 
     // Fling to delete
-    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
+    @Thunk int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
     private float FLING_TO_DELETE_FRICTION = 0.035f;
     // The degrees specifies how much deviation from the up vector to still consider a fling "up"
     private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
     protected int mFlingToDeleteThresholdVelocity = -1400;
     // Drag to delete
-    private boolean mDeferringForDelete = false;
-    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+    @Thunk boolean mDeferringForDelete = false;
+    @Thunk int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
     private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
 
     // Drop to delete
@@ -2356,7 +2358,7 @@
             super(superState);
         }
 
-        private SavedState(Parcel in) {
+        @Thunk SavedState(Parcel in) {
             super(in);
             currentPage = in.readInt();
         }
@@ -2514,7 +2516,7 @@
         invalidate();
     }
 
-    private void onPostReorderingAnimationCompleted() {
+    @Thunk void onPostReorderingAnimationCompleted() {
         // Trigger the callback when reordering has settled
         --mPostReorderingPreZoomInRemainingAnimationCount;
         if (mPostReorderingPreZoomInRunnable != null &&
diff --git a/src/com/android/launcher3/PagedViewCellLayout.java b/src/com/android/launcher3/PagedViewCellLayout.java
index 2d9e10b..e3ad9da 100644
--- a/src/com/android/launcher3/PagedViewCellLayout.java
+++ b/src/com/android/launcher3/PagedViewCellLayout.java
@@ -348,22 +348,6 @@
         requestLayout();
     }
 
-    /**
-     * Estimates the width that the number of hSpan cells will take up.
-     */
-    public int estimateCellWidth(int hSpan) {
-        // TODO: we need to take widthGap into effect
-        return hSpan * mCellWidth;
-    }
-
-    /**
-     * Estimates the height that the number of vSpan cells will take up.
-     */
-    public int estimateCellHeight(int vSpan) {
-        // TODO: we need to take heightGap into effect
-        return vSpan * mCellHeight;
-    }
-
     @Override
     public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
         return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index a879865..9d06f75 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -22,14 +22,8 @@
 import android.content.IntentFilter;
 import android.util.Log;
 
-import java.io.*;
-import java.util.ArrayList;
-
 public class Stats {
     private static final boolean DEBUG_BROADCASTS = false;
-    private static final String TAG = "Launcher3/Stats";
-
-    private static final boolean LOCAL_LAUNCH_LOG = true;
 
     public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
     public static final String EXTRA_INTENT = "intent";
@@ -38,54 +32,20 @@
     public static final String EXTRA_CELLX = "cellX";
     public static final String EXTRA_CELLY = "cellY";
 
-    private static final int LOG_VERSION = 1;
-    private static final int LOG_TAG_VERSION = 0x1;
-    private static final int LOG_TAG_LAUNCH = 0x1000;
-
-    private static final int STATS_VERSION = 1;
-    private static final int INITIAL_STATS_SIZE = 100;
-
-    // TODO: delayed/batched writes
-    private static final boolean FLUSH_IMMEDIATELY = true;
-
     private final Launcher mLauncher;
-
     private final String mLaunchBroadcastPermission;
 
-    DataOutputStream mLog;
-
-    ArrayList<String> mIntents;
-    ArrayList<Integer> mHistogram;
-
     public Stats(Launcher launcher) {
         mLauncher = launcher;
-
         mLaunchBroadcastPermission =
                 launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
 
-        loadStats();
-
-        if (LOCAL_LAUNCH_LOG) {
-            try {
-                mLog = new DataOutputStream(mLauncher.openFileOutput(
-                        LauncherFiles.LAUNCHES_LOG, Context.MODE_APPEND));
-                mLog.writeInt(LOG_TAG_VERSION);
-                mLog.writeInt(LOG_VERSION);
-            } catch (FileNotFoundException e) {
-                Log.e(TAG, "unable to create stats log: " + e);
-                mLog = null;
-            } catch (IOException e) {
-                Log.e(TAG, "unable to write to stats log: " + e);
-                mLog = null;
-            }
-        }
-
         if (DEBUG_BROADCASTS) {
             launcher.registerReceiver(
                     new BroadcastReceiver() {
                         @Override
                         public void onReceive(Context context, Intent intent) {
-                            android.util.Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
+                            Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
                                     + intent.getStringExtra(EXTRA_INTENT));
                         }
                     },
@@ -96,16 +56,6 @@
         }
     }
 
-    public void incrementLaunch(String intentStr) {
-        int pos = mIntents.indexOf(intentStr);
-        if (pos < 0) {
-            mIntents.add(intentStr);
-            mHistogram.add(1);
-        } else {
-            mHistogram.set(pos, mHistogram.get(pos) + 1);
-        }
-    }
-
     public void recordLaunch(Intent intent) {
         recordLaunch(intent, null);
     }
@@ -115,7 +65,6 @@
         intent.setSourceBounds(null);
 
         final String flat = intent.toUri(0);
-
         Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat);
         if (shortcut != null) {
             broadcastIntent.putExtra(EXTRA_CONTAINER, shortcut.container)
@@ -124,94 +73,5 @@
                     .putExtra(EXTRA_CELLY, shortcut.cellY);
         }
         mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
-
-        incrementLaunch(flat);
-
-        if (FLUSH_IMMEDIATELY) {
-            saveStats();
-        }
-
-        if (LOCAL_LAUNCH_LOG && mLog != null) {
-            try {
-                mLog.writeInt(LOG_TAG_LAUNCH);
-                mLog.writeLong(System.currentTimeMillis());
-                if (shortcut == null) {
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                } else {
-                    mLog.writeShort((short) shortcut.container);
-                    mLog.writeShort((short) shortcut.screenId);
-                    mLog.writeShort((short) shortcut.cellX);
-                    mLog.writeShort((short) shortcut.cellY);
-                }
-                mLog.writeUTF(flat);
-                if (FLUSH_IMMEDIATELY) {
-                    mLog.flush(); // TODO: delayed writes
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private void saveStats() {
-        DataOutputStream stats = null;
-        try {
-            stats = new DataOutputStream(mLauncher.openFileOutput(
-                    LauncherFiles.STATS_LOG + ".tmp", Context.MODE_PRIVATE));
-            stats.writeInt(STATS_VERSION);
-            final int N = mHistogram.size();
-            stats.writeInt(N);
-            for (int i=0; i<N; i++) {
-                stats.writeUTF(mIntents.get(i));
-                stats.writeInt(mHistogram.get(i));
-            }
-            stats.close();
-            stats = null;
-            mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG + ".tmp")
-                     .renameTo(mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG));
-        } catch (FileNotFoundException e) {
-            Log.e(TAG, "unable to create stats data: " + e);
-        } catch (IOException e) {
-            Log.e(TAG, "unable to write to stats data: " + e);
-        } finally {
-            if (stats != null) {
-                try {
-                    stats.close();
-                } catch (IOException e) { }
-            }
-        }
-    }
-
-    private void loadStats() {
-        mIntents = new ArrayList<String>(INITIAL_STATS_SIZE);
-        mHistogram = new ArrayList<Integer>(INITIAL_STATS_SIZE);
-        DataInputStream stats = null;
-        try {
-            stats = new DataInputStream(mLauncher.openFileInput(LauncherFiles.STATS_LOG));
-            final int version = stats.readInt();
-            if (version == STATS_VERSION) {
-                final int N = stats.readInt();
-                for (int i=0; i<N; i++) {
-                    final String pkg = stats.readUTF();
-                    final int count = stats.readInt();
-                    mIntents.add(pkg);
-                    mHistogram.add(count);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // not a problem
-        } catch (IOException e) {
-            // more of a problem
-
-        } finally {
-            if (stats != null) {
-                try {
-                    stats.close();
-                } catch (IOException e) { }
-            }
-        }
     }
 }
diff --git a/src/com/android/launcher3/WeightWatcher.java b/src/com/android/launcher3/WeightWatcher.java
index 70b8afe..7568479 100644
--- a/src/com/android/launcher3/WeightWatcher.java
+++ b/src/com/android/launcher3/WeightWatcher.java
@@ -34,6 +34,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 public class WeightWatcher extends LinearLayout {
     private static final int RAM_GRAPH_RSS_COLOR = 0xFF990000;
     private static final int RAM_GRAPH_PSS_COLOR = 0xFF99CC00;
@@ -81,7 +83,7 @@
             }
         }
     };
-    private MemoryTracker mMemoryService;
+    @Thunk MemoryTracker mMemoryService;
 
     public WeightWatcher(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -134,7 +136,7 @@
         GraphView mRamGraph;
         TextView mText;
         int mPid;
-        private MemoryTracker.ProcessMemInfo mMemInfo;
+        @Thunk MemoryTracker.ProcessMemInfo mMemInfo;
 
         public ProcessWatcher(Context context) {
             this(context, null);
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 3128140..0a5f0af 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -16,20 +16,21 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.Shader;
+import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.util.Log;
+
 import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.Thunk;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -46,107 +47,27 @@
 
 public class WidgetPreviewLoader {
 
-    private static abstract class SoftReferenceThreadLocal<T> {
-        private ThreadLocal<SoftReference<T>> mThreadLocal;
-        public SoftReferenceThreadLocal() {
-            mThreadLocal = new ThreadLocal<SoftReference<T>>();
-        }
-
-        abstract T initialValue();
-
-        public void set(T t) {
-            mThreadLocal.set(new SoftReference<T>(t));
-        }
-
-        public T get() {
-            SoftReference<T> reference = mThreadLocal.get();
-            T obj;
-            if (reference == null) {
-                obj = initialValue();
-                mThreadLocal.set(new SoftReference<T>(obj));
-                return obj;
-            } else {
-                obj = reference.get();
-                if (obj == null) {
-                    obj = initialValue();
-                    mThreadLocal.set(new SoftReference<T>(obj));
-                }
-                return obj;
-            }
-        }
-    }
-
-    private static class CanvasCache extends SoftReferenceThreadLocal<Canvas> {
-        @Override
-        protected Canvas initialValue() {
-            return new Canvas();
-        }
-    }
-
-    private static class PaintCache extends SoftReferenceThreadLocal<Paint> {
-        @Override
-        protected Paint initialValue() {
-            return null;
-        }
-    }
-
-    private static class BitmapCache extends SoftReferenceThreadLocal<Bitmap> {
-        @Override
-        protected Bitmap initialValue() {
-            return null;
-        }
-    }
-
-    private static class RectCache extends SoftReferenceThreadLocal<Rect> {
-        @Override
-        protected Rect initialValue() {
-            return new Rect();
-        }
-    }
-
-    private static class BitmapFactoryOptionsCache extends
-            SoftReferenceThreadLocal<BitmapFactory.Options> {
-        @Override
-        protected BitmapFactory.Options initialValue() {
-            return new BitmapFactory.Options();
-        }
-    }
-
     private static final String TAG = "WidgetPreviewLoader";
     private static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version";
 
     private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
-    private static final HashSet<String> sInvalidPackages = new HashSet<String>();
-
-    // Used for drawing shortcut previews
-    private final BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
-    private final PaintCache mCachedShortcutPreviewPaint = new PaintCache();
-    private final CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
-
-    // Used for drawing widget previews
-    private final CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
-    private final RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
-    private final RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
-    private final PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
-    private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
-    private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
+    @Thunk static final HashSet<String> sInvalidPackages = new HashSet<String>();
 
     private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
     private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>();
 
-    private final Context mContext;
     private final int mAppIconSize;
+    private final int mCellWidth;
+
+    private final Context mContext;
     private final IconCache mIconCache;
     private final AppWidgetManagerCompat mManager;
 
     private int mPreviewBitmapWidth;
     private int mPreviewBitmapHeight;
     private String mSize;
-    private PagedViewCellLayout mWidgetSpacingLayout;
 
     private String mCachedSelectQuery;
-
-
     private CacheDb mDb;
 
     private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
@@ -157,9 +78,10 @@
 
         mContext = context;
         mAppIconSize = grid.iconSizePx;
+        mCellWidth = grid.cellWidthPx;
+
         mIconCache = app.getIconCache();
         mManager = AppWidgetManagerCompat.getInstance(context);
-
         mDb = app.getWidgetPreviewCacheDb();
 
         SharedPreferences sp = context.getSharedPreferences(
@@ -193,12 +115,10 @@
         mDb = app.getWidgetPreviewCacheDb();
     }
 
-    public void setPreviewSize(int previewWidth, int previewHeight,
-            PagedViewCellLayout widgetSpacingLayout) {
+    public void setPreviewSize(int previewWidth, int previewHeight) {
         mPreviewBitmapWidth = previewWidth;
         mPreviewBitmapHeight = previewHeight;
         mSize = previewWidth + "x" + previewHeight;
-        mWidgetSpacingLayout = widgetSpacingLayout;
     }
 
     public Bitmap getPreview(final Object o) {
@@ -233,12 +153,6 @@
                     unusedBitmap = candidate;
                 }
             }
-            if (unusedBitmap != null) {
-                final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-                c.setBitmap(unusedBitmap);
-                c.drawColor(0, PorterDuff.Mode.CLEAR);
-                c.setBitmap(null);
-            }
         }
 
         if (unusedBitmap == null) {
@@ -362,7 +276,7 @@
         }
     }
 
-    private void writeToDb(Object o, Bitmap preview) {
+    @Thunk void writeToDb(Object o, Bitmap preview) {
         String name = getObjectName(o);
         SQLiteDatabase db = mDb.getWritableDatabase();
         ContentValues values = new ContentValues();
@@ -468,7 +382,7 @@
             result.moveToFirst();
             byte[] blob = result.getBlob(0);
             result.close();
-            final BitmapFactory.Options opts = mCachedBitmapFactoryOptions.get();
+            final BitmapFactory.Options opts = new BitmapFactory.Options();
             opts.inBitmap = b;
             opts.inSampleSize = 1;
             try {
@@ -499,26 +413,17 @@
 
     public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, Bitmap preview) {
         int maxWidth = maxWidthForWidgetPreview(info.spanX);
-        int maxHeight = maxHeightForWidgetPreview(info.spanY);
-        return generateWidgetPreview(info, info.spanX, info.spanY, maxWidth,
-                maxHeight, preview, null);
+        return generateWidgetPreview(info, maxWidth, preview, null);
     }
 
     public int maxWidthForWidgetPreview(int spanX) {
-        return Math.min(mPreviewBitmapWidth,
-                mWidgetSpacingLayout.estimateCellWidth(spanX));
+        return Math.min(mPreviewBitmapWidth, spanX * mCellWidth);
     }
 
-    public int maxHeightForWidgetPreview(int spanY) {
-        return Math.min(mPreviewBitmapHeight,
-                mWidgetSpacingLayout.estimateCellHeight(spanY));
-    }
-
-    public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info, int cellHSpan, int cellVSpan,
-            int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) {
+    public Bitmap generateWidgetPreview(LauncherAppWidgetProviderInfo info,
+            int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) {
         // Load the preview image if possible
         if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE;
-        if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE;
 
         Drawable drawable = null;
         if (info.previewImage != 0) {
@@ -531,61 +436,23 @@
             }
         }
 
+        final boolean widgetPreviewExists = (drawable != null);
+        final int spanX = info.spanX < 1 ? 1 : info.spanX;
+        final int spanY = info.spanY < 1 ? 1 : info.spanY;
+
         int previewWidth;
         int previewHeight;
-        Bitmap defaultPreview = null;
-        boolean widgetPreviewExists = (drawable != null);
+        Bitmap tileBitmap = null;
+
         if (widgetPreviewExists) {
             previewWidth = drawable.getIntrinsicWidth();
             previewHeight = drawable.getIntrinsicHeight();
         } else {
             // Generate a preview image if we couldn't load one
-            if (cellHSpan < 1) cellHSpan = 1;
-            if (cellVSpan < 1) cellVSpan = 1;
-
-            // This Drawable is not directly drawn, so there's no need to mutate it.
-            BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources()
-                    .getDrawable(R.drawable.widget_tile);
-            final int previewDrawableWidth = previewDrawable
-                    .getIntrinsicWidth();
-            final int previewDrawableHeight = previewDrawable
-                    .getIntrinsicHeight();
-            previewWidth = previewDrawableWidth * cellHSpan;
-            previewHeight = previewDrawableHeight * cellVSpan;
-
-            defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
-            final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-            c.setBitmap(defaultPreview);
-            Paint p = mDefaultAppWidgetPreviewPaint.get();
-            if (p == null) {
-                p = new Paint();
-                p.setShader(new BitmapShader(previewDrawable.getBitmap(),
-                        Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
-                mDefaultAppWidgetPreviewPaint.set(p);
-            }
-            final Rect dest = mCachedAppWidgetPreviewDestRect.get();
-            dest.set(0, 0, previewWidth, previewHeight);
-            c.drawRect(dest, p);
-            c.setBitmap(null);
-
-            // Draw the icon in the top left corner
-            int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE);
-            int smallestSide = Math.min(previewWidth, previewHeight);
-            float iconScale = Math.min((float) smallestSide
-                    / (mAppIconSize + 2 * minOffset), 1f);
-
-            try {
-                Drawable icon = mManager.loadIcon(info, mIconCache);
-                if (icon != null) {
-                    int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
-                    int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
-                    icon = mutateOnMainThread(icon);
-                    renderDrawableToBitmap(icon, defaultPreview, hoffset,
-                            yoffset, (int) (mAppIconSize * iconScale),
-                            (int) (mAppIconSize * iconScale));
-                }
-            } catch (Resources.NotFoundException e) {
-            }
+            tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable(
+                    R.drawable.widget_tile)).getBitmap();
+            previewWidth = tileBitmap.getWidth() * spanX;
+            previewHeight = tileBitmap.getHeight() * spanY;
         }
 
         // Scale to fit width only - let the widget preview be clipped in the
@@ -603,30 +470,58 @@
         }
 
         // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size
+        final Canvas c = new Canvas();
         if (preview == null) {
             preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
+            c.setBitmap(preview);
+        } else {
+            // Reusing bitmap. Clear it.
+            c.setBitmap(preview);
+            c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
 
         // Draw the scaled preview into the final bitmap
         int x = (preview.getWidth() - previewWidth) / 2;
         if (widgetPreviewExists) {
-            renderDrawableToBitmap(drawable, preview, x, 0, previewWidth,
-                    previewHeight);
+            drawable.setBounds(x, 0, x + previewWidth, previewHeight);
+            drawable.draw(c);
         } else {
-            final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-            final Rect src = mCachedAppWidgetPreviewSrcRect.get();
-            final Rect dest = mCachedAppWidgetPreviewDestRect.get();
-            c.setBitmap(preview);
-            src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight());
-            dest.set(x, 0, x + previewWidth, previewHeight);
+            final Paint p = new Paint();
+            p.setFilterBitmap(true);
 
-            Paint p = mCachedAppWidgetPreviewPaint.get();
-            if (p == null) {
-                p = new Paint();
-                p.setFilterBitmap(true);
-                mCachedAppWidgetPreviewPaint.set(p);
+            // draw the spanX x spanY tiles
+            final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight());
+
+            float tileW = scale * tileBitmap.getWidth();
+            float tileH = scale * tileBitmap.getHeight();
+            final RectF dst = new RectF(0, 0, tileW, tileH);
+
+            float tx = x;
+            for (int i = 0; i < spanX; i++, tx += tileW) {
+                float ty = 0;
+                for (int j = 0; j < spanY; j++, ty += tileH) {
+                    dst.offsetTo(tx, ty);
+                    c.drawBitmap(tileBitmap, src, dst, p);
+                }
             }
-            c.drawBitmap(defaultPreview, src, dest, p);
+
+            // Draw the icon in the top left corner
+            // TODO: use top right for RTL
+            int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE);
+            int smallestSide = Math.min(previewWidth, previewHeight);
+            float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), scale);
+
+            try {
+                Drawable icon = mutateOnMainThread(mManager.loadIcon(info, mIconCache));
+                if (icon != null) {
+                    int hoffset = (int) ((tileW - mAppIconSize * iconScale) / 2) + x;
+                    int yoffset = (int) ((tileH - mAppIconSize * iconScale) / 2);
+                    icon.setBounds(hoffset, yoffset,
+                            hoffset + (int) (mAppIconSize * iconScale),
+                            yoffset + (int) (mAppIconSize * iconScale));
+                    icon.draw(c);
+                }
+            } catch (Resources.NotFoundException e) { }
             c.setBitmap(null);
         }
         return mManager.getBadgeBitmap(info, preview);
@@ -634,71 +529,47 @@
 
     private Bitmap generateShortcutPreview(
             ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) {
-        Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get();
-        final Canvas c = mCachedShortcutPreviewCanvas.get();
-        if (tempBitmap == null ||
-                tempBitmap.getWidth() != maxWidth ||
-                tempBitmap.getHeight() != maxHeight) {
-            tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
-            mCachedShortcutPreviewBitmap.set(tempBitmap);
-        } else {
-            c.setBitmap(tempBitmap);
-            c.drawColor(0, PorterDuff.Mode.CLEAR);
-            c.setBitmap(null);
-        }
-        // Render the icon
-        Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo));
-
-        int paddingTop = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
-        int paddingLeft = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left);
-        int paddingRight = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
-
-        int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
-
-        renderDrawableToBitmap(
-                icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth);
-
-        if (preview != null &&
-                (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight)) {
-            throw new RuntimeException("Improperly sized bitmap passed as argument");
-        } else if (preview == null) {
+        final Canvas c = new Canvas();
+        if (preview == null) {
             preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
+            c.setBitmap(preview);
+        } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) {
+            throw new RuntimeException("Improperly sized bitmap passed as argument");
+        } else {
+            // Reusing bitmap. Clear it.
+            c.setBitmap(preview);
+            c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
 
-        c.setBitmap(preview);
+        Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo));
+        icon.setFilterBitmap(true);
+
         // Draw a desaturated/scaled version of the icon in the background as a watermark
-        Paint p = mCachedShortcutPreviewPaint.get();
-        if (p == null) {
-            p = new Paint();
-            ColorMatrix colorMatrix = new ColorMatrix();
-            colorMatrix.setSaturation(0);
-            p.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
-            p.setAlpha((int) (255 * 0.06f));
-            mCachedShortcutPreviewPaint.set(p);
-        }
-        c.drawBitmap(tempBitmap, 0, 0, p);
+        ColorMatrix colorMatrix = new ColorMatrix();
+        colorMatrix.setSaturation(0);
+        icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
+        icon.setAlpha((int) (255 * 0.06f));
+
+        Resources res = mContext.getResources();
+        int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
+        int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left);
+        int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
+        int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
+        icon.setBounds(paddingLeft, paddingTop,
+                paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth);
+        icon.draw(c);
+
+        // Draw the final icon at top left corner.
+        // TODO: use top right for RTL
+        icon.setAlpha(255);
+        icon.setColorFilter(null);
+        icon.setBounds(0, 0, mAppIconSize, mAppIconSize);
+        icon.draw(c);
+
         c.setBitmap(null);
-
-        renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize);
-
         return preview;
     }
 
-    private static void renderDrawableToBitmap(
-            Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
-        if (bitmap != null) {
-            Canvas c = new Canvas(bitmap);
-            Rect oldBounds = d.copyBounds();
-            d.setBounds(x, y, x + w, y + h);
-            d.draw(c);
-            d.setBounds(oldBounds); // Restore the bounds
-            c.setBitmap(null);
-        }
-    }
-
     private Drawable mutateOnMainThread(final Drawable drawable) {
         try {
             return mMainThreadExecutor.submit(new Callable<Drawable>() {
@@ -720,7 +591,7 @@
     /**
      * Dumps all files that are open in this process without allocating a file descriptor.
      */
-    private static void dumpOpenFiles() {
+    @Thunk static void dumpOpenFiles() {
         try {
             Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):");
             final String TYPE_APK = "apk";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7ebdf3a..37265fe 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -69,6 +69,7 @@
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -117,24 +118,24 @@
     private long mCustomContentShowTime = -1;
 
     private LayoutTransition mLayoutTransition;
-    private final WallpaperManager mWallpaperManager;
-    private IBinder mWindowToken;
+    @Thunk final WallpaperManager mWallpaperManager;
+    @Thunk IBinder mWindowToken;
 
     private int mOriginalDefaultPage;
     private int mDefaultPage;
 
     private ShortcutAndWidgetContainer mDragSourceInternal;
-    private static boolean sAccessibilityEnabled;
+    @Thunk static boolean sAccessibilityEnabled;
 
     // The screen id used for the empty screen always present to the right.
     final static long EXTRA_EMPTY_SCREEN_ID = -201;
     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
 
-    private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
-    private ArrayList<Long> mScreenOrder = new ArrayList<Long>();
+    @Thunk HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
+    @Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>();
 
-    private Runnable mRemoveEmptyScreenRunnable;
-    private boolean mDeferRemoveExtraEmptyScreen = false;
+    @Thunk Runnable mRemoveEmptyScreenRunnable;
+    @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -144,7 +145,7 @@
     /**
      * Target drop area calculated during last acceptDrop call.
      */
-    private int[] mTargetCell = new int[2];
+    @Thunk int[] mTargetCell = new int[2];
     private int mDragOverX = -1;
     private int mDragOverY = -1;
 
@@ -159,7 +160,7 @@
     /**
      * The CellLayout that is currently being dragged over
      */
-    private CellLayout mDragTargetLayout = null;
+    @Thunk CellLayout mDragTargetLayout = null;
     /**
      * The CellLayout that we will show as glowing
      */
@@ -170,16 +171,16 @@
      */
     private CellLayout mDropToLayout = null;
 
-    private Launcher mLauncher;
-    private IconCache mIconCache;
-    private DragController mDragController;
+    @Thunk Launcher mLauncher;
+    @Thunk IconCache mIconCache;
+    @Thunk DragController mDragController;
 
     // These are temporary variables to prevent having to allocate a new object just to
     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
     private int[] mTempCell = new int[2];
     private int[] mTempPt = new int[2];
     private int[] mTempEstimate = new int[2];
-    private float[] mDragViewVisualCenter = new float[2];
+    @Thunk float[] mDragViewVisualCenter = new float[2];
     private float[] mTempCellLayoutCenterCoordinates = new float[2];
     private Matrix mTempInverseMatrix = new Matrix();
 
@@ -204,7 +205,7 @@
     private boolean mInScrollArea = false;
 
     private HolographicOutlineHelper mOutlineHelper;
-    private Bitmap mDragOutline = null;
+    @Thunk Bitmap mDragOutline = null;
     private static final Rect sTempRect = new Rect();
     private final int[] mTempXY = new int[2];
     private int[] mTempVisiblePagesRange = new int[2];
@@ -213,11 +214,11 @@
     private boolean mWorkspaceFadeInAdjacentScreens;
 
     WallpaperOffsetInterpolator mWallpaperOffset;
-    private boolean mWallpaperIsLiveWallpaper;
-    private int mNumPagesForWallpaperParallax;
-    private float mLastSetWallpaperOffsetSteps = 0;
+    @Thunk boolean mWallpaperIsLiveWallpaper;
+    @Thunk int mNumPagesForWallpaperParallax;
+    @Thunk float mLastSetWallpaperOffsetSteps = 0;
 
-    private Runnable mDelayedResizeRunnable;
+    @Thunk Runnable mDelayedResizeRunnable;
     private Runnable mDelayedSnapToPageRunnable;
     private Point mDisplaySize = new Point();
 
@@ -226,7 +227,7 @@
     public static final int REORDER_TIMEOUT = 350;
     private final Alarm mFolderCreationAlarm = new Alarm();
     private final Alarm mReorderAlarm = new Alarm();
-    private FolderRingAnimator mDragFolderRingAnimator = null;
+    @Thunk FolderRingAnimator mDragFolderRingAnimator = null;
     private FolderIcon mDragOverFolderIcon = null;
     private boolean mCreateUserFolderOnDrop = false;
     private boolean mAddToExistingFolderOnDrop = false;
@@ -255,8 +256,8 @@
     private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
     private static final int DRAG_MODE_REORDER = 3;
     private int mDragMode = DRAG_MODE_NONE;
-    private int mLastReorderX = -1;
-    private int mLastReorderY = -1;
+    @Thunk int mLastReorderX = -1;
+    @Thunk int mLastReorderY = -1;
 
     private SparseArray<Parcelable> mSavedStates;
     private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();
@@ -268,17 +269,17 @@
 
     private float mCurrentScale;
     private float mNewScale;
-    private float[] mOldBackgroundAlphas;
+    @Thunk float[] mOldBackgroundAlphas;
     private float[] mOldAlphas;
-    private float[] mNewBackgroundAlphas;
+    @Thunk float[] mNewBackgroundAlphas;
     private float[] mNewAlphas;
     private int mLastChildCount = -1;
     private float mTransitionProgress;
-    private Animator mStateAnimator = null;
+    @Thunk Animator mStateAnimator = null;
 
     float mOverScrollEffect = 0f;
 
-    private Runnable mDeferredAction;
+    @Thunk Runnable mDeferredAction;
     private boolean mDeferDropAfterUninstall;
     private boolean mUninstallSuccessful;
 
@@ -1882,7 +1883,7 @@
         }
     }
 
-    private void updateChildrenLayersEnabled(boolean force) {
+    @Thunk void updateChildrenLayersEnabled(boolean force) {
         boolean small = mState == State.OVERVIEW || mIsSwitchingState;
         boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
 
@@ -2571,7 +2572,7 @@
         }
     }
 
-    private void onTransitionEnd() {
+    @Thunk void onTransitionEnd() {
         mIsSwitchingState = false;
         updateChildrenLayersEnabled(false);
         showCustomContentIfNecessary();
@@ -4186,7 +4187,7 @@
      *
      * pixelX and pixelY should be in the coordinate system of layout
      */
-    private int[] findNearestArea(int pixelX, int pixelY,
+    @Thunk int[] findNearestArea(int pixelX, int pixelY,
             int spanX, int spanY, CellLayout layout, int[] recycle) {
         return layout.findNearestArea(
                 pixelX, pixelY, spanX, spanY, recycle);
@@ -4878,7 +4879,8 @@
             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
                     mLauncher.getAppWidgetHost());
             if (LauncherModel.getProviderInfo(getContext(),
-                    changedInfo.get(0).providerName) != null) {
+                    changedInfo.get(0).providerName,
+                    changedInfo.get(0).user) != null) {
                 // Re-inflate the widgets which have changed status
                 widgetRefresh.run();
             } else {
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
index e47b9a5..ac3d252 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -31,6 +31,8 @@
 import android.os.Bundle;
 import android.provider.Settings;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -139,11 +141,11 @@
         mContext.registerReceiver(mPackageMonitor, filter);
     }
 
-    private synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
+    @Thunk synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
         return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
     }
 
-    private class PackageMonitor extends BroadcastReceiver {
+    @Thunk class PackageMonitor extends BroadcastReceiver {
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             final UserHandleCompat user = UserHandleCompat.myUserHandle();
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 601f04c..d6d4b82 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -26,6 +26,7 @@
 
 import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -36,10 +37,10 @@
     private static final boolean DEBUG = false;
 
     // All updates to these sets must happen on the {@link #mWorker} thread.
-    private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
-    private final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
+    @Thunk final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
+    @Thunk final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
 
-    private final PackageInstaller mInstaller;
+    @Thunk final PackageInstaller mInstaller;
     private final IconCache mCache;
     private final Handler mWorker;
 
@@ -82,7 +83,7 @@
         return activePackages;
     }
 
-    private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
+    @Thunk void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
         String packageName = info.getAppPackageName();
         if (packageName != null) {
             mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(),
@@ -123,7 +124,7 @@
         replayUpdates(null);
     }
 
-    private void replayUpdates(PackageInstallInfo newInfo) {
+    @Thunk void replayUpdates(PackageInstallInfo newInfo) {
         if (DEBUG) Log.d(TAG, "updates resumed");
         if (!mResumed || !mBound) {
             // Not yet ready
diff --git a/src/com/android/launcher3/util/Thunk.java b/src/com/android/launcher3/util/Thunk.java
new file mode 100644
index 0000000..de350b0
--- /dev/null
+++ b/src/com/android/launcher3/util/Thunk.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the given field or method has package visibility solely to prevent the creation
+ * of a synthetic method. In practice, you should treat this field/method as if it were private.
+ * <p>
+ *
+ * When a private method is called from an inner class, the Java compiler generates a simple
+ * package private shim method that the class generated from the inner class can call. This results
+ * in unnecessary bloat and runtime method call overhead. It also gets us closer to the dex method
+ * count limit.
+ * <p>
+ *
+ * If you'd like to see warnings for these synthetic methods in eclipse, turn on:
+ * Window > Preferences > Java > Compiler > Errors/Warnings > "Access to a non-accessible member
+ * of an enclosing type".
+ * <p>
+ *
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE})
+public @interface Thunk { }
\ No newline at end of file