Merge "Import translations. DO NOT MERGE" into jb-ub-now-kermit
diff --git a/Android.mk b/Android.mk
index 6059a3f..840b161 100644
--- a/Android.mk
+++ b/Android.mk
@@ -61,6 +61,28 @@
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
 
 LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := protoutil
+LOCAL_MODULE := launcher_protoutil_lib
+LOCAL_IS_HOST_MODULE := true
+LOCAL_JAR_MANIFEST := util/etc/manifest.txt
+LOCAL_STATIC_JAVA_LIBRARIES := host-libprotobuf-java-2.3.0-nano
 
 include $(BUILD_HOST_JAVA_LIBRARY)
+
+#
+# Protocol Buffer Debug Utility Wrapper Script
+#
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := launcher_protoutil
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): launcher_protoutil_lib
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/util/etc/launcher_protoutil | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
diff --git a/res/drawable-sw720dp-hdpi/workspace_bg.9.png b/res/drawable-sw720dp-hdpi/workspace_bg.9.png
new file mode 100644
index 0000000..5bbfa4f
--- /dev/null
+++ b/res/drawable-sw720dp-hdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-sw720dp-mdpi/workspace_bg.9.png b/res/drawable-sw720dp-mdpi/workspace_bg.9.png
new file mode 100644
index 0000000..2856e09
--- /dev/null
+++ b/res/drawable-sw720dp-mdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-sw720dp-xhdpi/workspace_bg.9.png b/res/drawable-sw720dp-xhdpi/workspace_bg.9.png
new file mode 100644
index 0000000..72269f2
--- /dev/null
+++ b/res/drawable-sw720dp-xhdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png b/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png
new file mode 100644
index 0000000..efc9b04
--- /dev/null
+++ b/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/values-land/config.xml b/res/values-land/config.xml
index 121bb0c..31115c9 100644
--- a/res/values-land/config.xml
+++ b/res/values-land/config.xml
@@ -18,6 +18,4 @@
 <!-- Workspace -->
     <!-- Whether or not the drop targets drop down as opposed to fade in -->
     <bool name="config_useDropTargetDownTransition">false</bool>
-    <!-- Whether or not to fade the side pages -->
-    <bool name="config_workspaceFadeAdjacentScreens">false</bool>
 </resources>
diff --git a/res/values-sw340dp-port/config.xml b/res/values-sw340dp-port/config.xml
index d31ee59..5f71077 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/values-sw340dp-port/config.xml
@@ -15,7 +15,4 @@
 -->
 
 <resources>
-<!-- Workspace -->
-    <!-- Whether or not to fade the side pages -->
-    <bool name="config_workspaceFadeAdjacentScreens">false</bool>
 </resources>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index 4f537a9..c00b594 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -9,8 +9,6 @@
 <!-- Workspace -->
     <!-- Whether or not the drop targets drop down as opposed to fade in -->
     <bool name="config_useDropTargetDownTransition">false</bool>
-    <!-- Whether or not to fade the side pages -->
-    <bool name="config_workspaceFadeAdjacentScreens">true</bool>
 
     <!-- Camera distance for the overscroll effect -->
     <integer name="config_cameraDistance">18000</integer>
diff --git a/res/values/config.xml b/res/values/config.xml
index 1538d9f..2a08216 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -52,8 +52,6 @@
 <!-- Workspace -->
     <!-- Whether or not the drop targets drop down as opposed to fade in -->
     <bool name="config_useDropTargetDownTransition">false</bool>
-    <!-- Whether or not to fade the side pages -->
-    <bool name="config_workspaceFadeAdjacentScreens">false</bool>
 
     <!-- The transition duration for the background of the drop targets -->
     <integer name="config_dropTargetBgTransitionDuration">0</integer>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index a05dd90..05e31af 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -100,6 +100,7 @@
     private int mForegroundAlpha = 0;
     private float mBackgroundAlpha;
     private float mBackgroundAlphaMultiplier = 1.0f;
+    private boolean mDrawBackground = true;
 
     private Drawable mNormalBackground;
     private Drawable mActiveGlowBackground;
@@ -388,6 +389,10 @@
         mUseActiveGlowBackground = use;
     }
 
+    void disableBackground() {
+        mDrawBackground = false;
+    }
+
     boolean getIsDragOverlapping() {
         return mIsDragOverlapping;
     }
@@ -416,7 +421,7 @@
         // When we're small, we are either drawn normally or in the "accepts drops" state (during
         // a drag). However, we also drag the mini hover background *over* one of those two
         // backgrounds
-        if (mBackgroundAlpha > 0.0f) {
+        if (mDrawBackground && mBackgroundAlpha > 0.0f) {
             Drawable bg;
 
             if (mUseActiveGlowBackground) {
@@ -2632,9 +2637,9 @@
         }
 
         if (mode == MODE_SHOW_REORDER_HINT) {
-            beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 0,
-                    ReorderPreviewAnimation.MODE_HINT);
             if (finalSolution != null) {
+                beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 0,
+                        ReorderPreviewAnimation.MODE_HINT);
                 result[0] = finalSolution.dragViewX;
                 result[1] = finalSolution.dragViewY;
                 resultSpan[0] = finalSolution.dragViewSpanX;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 511b718..67b0933 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -119,6 +119,8 @@
     int searchBarHeightPx;
     int pageIndicatorHeightPx;
 
+    float dragViewScale;
+
     private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
 
     DeviceProfile(String n, float w, float h, float r, float c,
@@ -282,11 +284,12 @@
 
         // Check to see if the icons fit in the new available height.  If not, then we need to
         // shrink the icon size.
-        Rect workspacePadding = getWorkspacePadding();
         float scale = 1f;
         int drawablePadding = iconDrawablePaddingOriginalPx;
         updateIconSize(1f, drawablePadding, resources, dm);
         float usedHeight = (cellHeightPx * numRows);
+
+        Rect workspacePadding = getWorkspacePadding();
         int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
         if (usedHeight > maxHeight) {
             scale = maxHeight / usedHeight;
@@ -319,6 +322,8 @@
         FontMetrics fm = textPaint.getFontMetrics();
         cellWidthPx = iconSizePx;
         cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top);
+        final float scaleDps = resources.getDimensionPixelSize(R.dimen.dragViewScale);
+        dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
 
         // Hotseat
         hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
@@ -491,17 +496,21 @@
             if (isTablet()) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
+                float gapScale = 1f + (dragViewScale - 1f) / 2f;
                 int width = (orientation == CellLayout.LANDSCAPE)
                         ? Math.max(widthPx, heightPx)
                         : Math.min(widthPx, heightPx);
-                // XXX: If the icon size changes across orientations, we will have to take
-                //      that into account here too.
-                int gap = (int) ((width - 2 * edgeMarginPx -
-                        (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
-                padding.set(edgeMarginPx + gap,
-                        searchBarBounds.bottom,
-                        edgeMarginPx + gap,
-                        hotseatBarHeightPx + pageIndicatorHeightPx);
+                int height = (orientation != CellLayout.LANDSCAPE)
+                        ? Math.max(widthPx, heightPx)
+                        : Math.min(widthPx, heightPx);
+                int paddingTop = searchBarBounds.bottom;
+                int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
+                int availableWidth = Math.max(0, width - (int) ((numColumns * cellWidthPx) +
+                        (numColumns * gapScale * cellWidthPx)));
+                int availableHeight = Math.max(0, height - paddingTop - paddingBottom
+                        - (int) (2 * numRows * cellHeightPx));
+                padding.set(availableWidth / 2, paddingTop + availableHeight / 2,
+                        availableWidth / 2, paddingBottom + availableHeight / 2);
             } else {
                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
                 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
@@ -514,8 +523,8 @@
     }
 
     int getWorkspacePageSpacing(int orientation) {
-        if (orientation == CellLayout.LANDSCAPE &&
-                transposeLayoutWithOrientation) {
+        if ((orientation == CellLayout.LANDSCAPE &&
+                transposeLayoutWithOrientation) || isLargeTablet()) {
             // In landscape mode the page spacing is set to the default.
             return defaultPageSpacingPx;
         } else {
@@ -645,19 +654,12 @@
             lp.height = LayoutParams.MATCH_PARENT;
             hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
         } else if (isTablet()) {
-            // Pad the hotseat with the grid gap calculated above
-            int gridGap = (int) ((widthPx - 2 * edgeMarginPx -
-                    (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
-            int gridWidth = (int) ((numColumns * cellWidthPx) +
-                    ((numColumns - 1) * gridGap));
-            int hotseatGap = (int) Math.max(0,
-                    (gridWidth - (numHotseatIcons * hotseatCellWidthPx))
-                            / (numHotseatIcons - 1));
+            // Pad the hotseat with the workspace padding calculated above
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
             lp.height = hotseatBarHeightPx;
-            hotseat.setPadding(2 * edgeMarginPx + gridGap + hotseatGap, 0,
-                    2 * edgeMarginPx + gridGap + hotseatGap,
+            hotseat.setPadding(edgeMarginPx + padding.left, 0,
+                    edgeMarginPx + padding.right,
                     2 * edgeMarginPx);
         } else {
             // For phones, layout the hotseat without any bottom margin
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index dc01c69..22928cc 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -74,10 +74,10 @@
         // The tablet profile is odd in that the landscape orientation
         // also includes the nav bar on the side
         deviceProfiles.add(new DeviceProfile("Nexus 7",
-                575, 904,  5, 5,  72, 14.4f,  7, 60));
+                575, 904,  5, 6,  72, 14.4f,  7, 60));
         // Larger tablet profiles always have system bars on the top & bottom
         deviceProfiles.add(new DeviceProfile("Nexus 10",
-                727, 1207,  5, 5,  80, 14.4f,  7, 64));
+                727, 1207,  5, 6,  76, 14.4f,  7, 64));
         /*
         deviceProfiles.add(new DeviceProfile("Nexus 7",
                 600, 960,  5, 5,  72, 14.4f,  5, 60));
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index cb2d23b..da805a0 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1532,16 +1532,9 @@
             }
         }
 
-        private boolean checkItemDimensions(ItemInfo info) {
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            return (info.cellX + info.spanX) > (int) grid.numColumns ||
-                    (info.cellY + info.spanY) > (int) grid.numRows;
-        }
-
         // check & update map of what's occupied; used to discard overlapping/invalid items
         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,
-                                           AtomicBoolean deleteOnItemOverlap) {
+                                           AtomicBoolean deleteOnInvalidPlacement) {
             LauncherAppState app = LauncherAppState.getInstance();
             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
             final int countX = (int) grid.numColumns;
@@ -1552,7 +1545,7 @@
                 // Return early if we detect that an item is under the hotseat button
                 if (mCallbacks == null ||
                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {
-                    deleteOnItemOverlap.set(true);
+                    deleteOnInvalidPlacement.set(true);
                     Log.e(TAG, "Error loading shortcut into hotseat " + item
                             + " into position (" + item.screenId + ":" + item.cellX + ","
                             + item.cellY + ") occupied by all apps");
@@ -1562,6 +1555,14 @@
                 final ItemInfo[][] hotseatItems =
                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
 
+                if (item.screenId >= grid.numHotseatIcons) {
+                    Log.e(TAG, "Error loading shortcut " + item
+                            + " into hotseat position " + item.screenId
+                            + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)
+                            + ")");
+                    return false;
+                }
+
                 if (hotseatItems != null) {
                     if (hotseatItems[(int) item.screenId][0] != null) {
                         Log.e(TAG, "Error loading shortcut into hotseat " + item
@@ -1575,7 +1576,7 @@
                         return true;
                     }
                 } else {
-                    final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons + 1][1];
+                    final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];
                     items[(int) item.screenId][0] = item;
                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);
                     return true;
@@ -1591,6 +1592,16 @@
             }
 
             final ItemInfo[][] screens = occupied.get(item.screenId);
+            if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+                    item.cellX < 0 || item.cellY < 0 ||
+                    item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
+                Log.e(TAG, "Error loading shortcut " + item
+                        + " into cell (" + containerIndex + "-" + item.screenId + ":"
+                        + item.cellX + "," + item.cellY
+                        + ") out of screen bounds ( " + countX + "x" + countY + ")");
+                return false;
+            }
+
             // Check if any workspace icons overlap with each other
             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
@@ -1709,7 +1720,7 @@
                     Intent intent;
 
                     while (!mStopped && c.moveToNext()) {
-                        AtomicBoolean deleteOnItemOverlap = new AtomicBoolean(false);
+                        AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);
                         try {
                             int itemType = c.getInt(itemTypeIndex);
 
@@ -1770,18 +1781,11 @@
                                     info.cellY = c.getInt(cellYIndex);
                                     info.spanX = 1;
                                     info.spanY = 1;
-                                    // Skip loading items that are out of bounds
-                                    if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                                        if (checkItemDimensions(info)) {
-                                            Launcher.addDumpLog(TAG, "Skipped loading out of bounds shortcut: "
-                                                    + info + ", " + grid.numColumns + "x" + grid.numRows, true);
-                                            continue;
-                                        }
-                                    }
+
                                     // check & update map of what's occupied
-                                    deleteOnItemOverlap.set(false);
-                                    if (!checkItemPlacement(occupied, info, deleteOnItemOverlap)) {
-                                        if (deleteOnItemOverlap.get()) {
+                                    deleteOnInvalidPlacement.set(false);
+                                    if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)) {
+                                        if (deleteOnInvalidPlacement.get()) {
                                             itemsToRemove.add(id);
                                         }
                                         break;
@@ -1823,18 +1827,11 @@
                                 folderInfo.spanX = 1;
                                 folderInfo.spanY = 1;
 
-                                // Skip loading items that are out of bounds
-                                if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                                    if (checkItemDimensions(folderInfo)) {
-                                        Log.d(TAG, "Skipped loading out of bounds folder");
-                                        continue;
-                                    }
-                                }
                                 // check & update map of what's occupied
-                                deleteOnItemOverlap.set(false);
+                                deleteOnInvalidPlacement.set(false);
                                 if (!checkItemPlacement(occupied, folderInfo,
-                                        deleteOnItemOverlap)) {
-                                    if (deleteOnItemOverlap.get()) {
+                                        deleteOnInvalidPlacement)) {
+                                    if (deleteOnInvalidPlacement.get()) {
                                         itemsToRemove.add(id);
                                     }
                                     break;
@@ -1890,18 +1887,11 @@
                                     }
 
                                     appWidgetInfo.container = c.getInt(containerIndex);
-                                    // Skip loading items that are out of bounds
-                                    if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                                        if (checkItemDimensions(appWidgetInfo)) {
-                                            Log.d(TAG, "Skipped loading out of bounds app widget");
-                                            continue;
-                                        }
-                                    }
                                     // check & update map of what's occupied
-                                    deleteOnItemOverlap.set(false);
+                                    deleteOnInvalidPlacement.set(false);
                                     if (!checkItemPlacement(occupied, appWidgetInfo,
-                                            deleteOnItemOverlap)) {
-                                        if (deleteOnItemOverlap.get()) {
+                                            deleteOnInvalidPlacement)) {
+                                        if (deleteOnInvalidPlacement.get()) {
                                             itemsToRemove.add(id);
                                         }
                                         break;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 72399e4..2e944a2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -565,6 +565,7 @@
     public void createCustomContentPage() {
         CellLayout customScreen = (CellLayout)
                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
+        customScreen.disableBackground();
 
         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);
         mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);
@@ -1155,11 +1156,6 @@
             }
         }
 
-        // Only show page outlines as we pan if we are on large screen
-        if (LauncherAppState.getInstance().isScreenLarge()) {
-            showOutlines();
-        }
-
         // If we are not fading in adjacent screens, we still need to restore the alpha in case the
         // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
         if (!mWorkspaceFadeInAdjacentScreens) {
@@ -1184,11 +1180,6 @@
                 // is under a new page (to scroll to)
                 mDragController.forceTouchMove();
             }
-        } else {
-            // If we are not mid-dragging, hide the page outlines if we are on a large screen
-            if (LauncherAppState.getInstance().isScreenLarge()) {
-                hideOutlines();
-            }
         }
 
         if (mDelayedResizeRunnable != null) {
@@ -3115,13 +3106,11 @@
         display.getCurrentSizeRange(smallestSize, largestSize);
         int countX = (int) grid.numColumns;
         int countY = (int) grid.numRows;
-        int constrainedLongEdge = largestSize.y;
-        int constrainedShortEdge = smallestSize.y;
         if (orientation == CellLayout.LANDSCAPE) {
             if (mLandscapeCellLayoutMetrics == null) {
                 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);
-                int width = constrainedLongEdge - padding.left - padding.right;
-                int height = constrainedShortEdge - padding.top - padding.bottom;
+                int width = largestSize.x - padding.left - padding.right;
+                int height = smallestSize.y - padding.top - padding.bottom;
                 mLandscapeCellLayoutMetrics = new Rect();
                 mLandscapeCellLayoutMetrics.set(
                         grid.calculateCellWidth(width, countX),
@@ -3131,8 +3120,8 @@
         } else if (orientation == CellLayout.PORTRAIT) {
             if (mPortraitCellLayoutMetrics == null) {
                 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);
-                int width = constrainedShortEdge - padding.left - padding.right;
-                int height = constrainedLongEdge - padding.top - padding.bottom;
+                int width = smallestSize.x - padding.left - padding.right;
+                int height = largestSize.y - padding.top - padding.bottom;
                 mPortraitCellLayoutMetrics = new Rect();
                 mPortraitCellLayoutMetrics.set(
                         grid.calculateCellWidth(width, countX),
diff --git a/update_system_wallpaper_cropper.py b/update_system_wallpaper_cropper.py
index 5d24f6f..36904f2 100644
--- a/update_system_wallpaper_cropper.py
+++ b/update_system_wallpaper_cropper.py
@@ -5,42 +5,43 @@
 # necessary so do this with care
 import os
 import sys
+src_dir = "wallpaper_picker_src/"
 files = """
 src/android/util/Pools.java
-src/com/android/gallery3d/util/IntArray.java
-src/com/android/gallery3d/common/Utils.java
-src/com/android/gallery3d/exif/ByteBufferInputStream.java
-src/com/android/gallery3d/exif/CountedDataInputStream.java
-src/com/android/gallery3d/exif/ExifData.java
-src/com/android/gallery3d/exif/ExifInterface.java
-src/com/android/gallery3d/exif/ExifInvalidFormatException.java
-src/com/android/gallery3d/exif/ExifModifier.java
-src/com/android/gallery3d/exif/ExifOutputStream.java
-src/com/android/gallery3d/exif/ExifParser.java
-src/com/android/gallery3d/exif/ExifReader.java
-src/com/android/gallery3d/exif/ExifTag.java
-src/com/android/gallery3d/exif/IfdData.java
-src/com/android/gallery3d/exif/IfdId.java
-src/com/android/gallery3d/exif/JpegHeader.java
-src/com/android/gallery3d/exif/OrderedDataOutputStream.java
-src/com/android/gallery3d/exif/Rational.java
-src/com/android/gallery3d/glrenderer/BasicTexture.java
-src/com/android/gallery3d/glrenderer/BitmapTexture.java
-src/com/android/gallery3d/glrenderer/GLCanvas.java
-src/com/android/gallery3d/glrenderer/GLES20Canvas.java
-src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
-src/com/android/gallery3d/glrenderer/GLId.java
-src/com/android/gallery3d/glrenderer/GLPaint.java
-src/com/android/gallery3d/glrenderer/RawTexture.java
-src/com/android/gallery3d/glrenderer/Texture.java
-src/com/android/gallery3d/glrenderer/UploadedTexture.java
-src/com/android/photos/BitmapRegionTileSource.java
-src/com/android/photos/views/BlockingGLTextureView.java
-src/com/android/photos/views/TiledImageRenderer.java
-src/com/android/photos/views/TiledImageView.java
-src/com/android/gallery3d/common/BitmapUtils.java
-src/com/android/launcher3/CropView.java
-src/com/android/launcher3/WallpaperCropActivity.java
+com/android/gallery3d/util/IntArray.java
+com/android/gallery3d/common/Utils.java
+com/android/gallery3d/exif/ByteBufferInputStream.java
+com/android/gallery3d/exif/CountedDataInputStream.java
+com/android/gallery3d/exif/ExifData.java
+com/android/gallery3d/exif/ExifInterface.java
+com/android/gallery3d/exif/ExifInvalidFormatException.java
+com/android/gallery3d/exif/ExifModifier.java
+com/android/gallery3d/exif/ExifOutputStream.java
+com/android/gallery3d/exif/ExifParser.java
+com/android/gallery3d/exif/ExifReader.java
+com/android/gallery3d/exif/ExifTag.java
+com/android/gallery3d/exif/IfdData.java
+com/android/gallery3d/exif/IfdId.java
+com/android/gallery3d/exif/JpegHeader.java
+com/android/gallery3d/exif/OrderedDataOutputStream.java
+com/android/gallery3d/exif/Rational.java
+com/android/gallery3d/glrenderer/BasicTexture.java
+com/android/gallery3d/glrenderer/BitmapTexture.java
+com/android/gallery3d/glrenderer/GLCanvas.java
+com/android/gallery3d/glrenderer/GLES20Canvas.java
+com/android/gallery3d/glrenderer/GLES20IdImpl.java
+com/android/gallery3d/glrenderer/GLId.java
+com/android/gallery3d/glrenderer/GLPaint.java
+com/android/gallery3d/glrenderer/RawTexture.java
+com/android/gallery3d/glrenderer/Texture.java
+com/android/gallery3d/glrenderer/UploadedTexture.java
+com/android/photos/BitmapRegionTileSource.java
+com/android/photos/views/BlockingGLTextureView.java
+com/android/photos/views/TiledImageRenderer.java
+com/android/photos/views/TiledImageView.java
+com/android/gallery3d/common/BitmapUtils.java
+com/android/launcher3/CropView.java
+com/android/launcher3/WallpaperCropActivity.java
 """
 
 if len(sys.argv) != 2:
@@ -48,8 +49,10 @@
     exit()
 framework_dir = sys.argv[1] + "/packages/WallpaperCropper"
 for file_path in files.split():
+    file_path = src_dir + file_path
     dir = os.path.dirname(file_path)
     dir = dir.replace("launcher3", "wallpapercropper")
+    dir = dir.replace(src_dir, "src/")
     cmd = 'cp %s %s/%s' % (file_path, framework_dir, dir)
     print cmd
     os.system(cmd)
diff --git a/util/com/android/launcher3/DecoderRing.java b/util/com/android/launcher3/DecoderRing.java
index 1d9e0de..bd0275e 100644
--- a/util/com/android/launcher3/DecoderRing.java
+++ b/util/com/android/launcher3/DecoderRing.java
@@ -49,7 +49,7 @@
     public static void main(String[ ] args)
             throws Exception {
         File source = null;
-        Class type = Key.class;
+        Class type = null;
         int skip = 0;
 
         for (int i = 0; i < args.length; i++) {
@@ -79,6 +79,9 @@
             }
         }
 
+        if (type == null) {
+            usage(args);
+        }
 
         // read in the bytes
         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
diff --git a/util/etc/launcher_protoutil b/util/etc/launcher_protoutil
new file mode 100644
index 0000000..833b583
--- /dev/null
+++ b/util/etc/launcher_protoutil
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=launcher_protoutil_lib.jar
+libdir="$progdir"
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    # set jar location for the Android tree case
+    libdir=`dirname "$progdir"`/framework
+fi
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    echo `basename "$prog"`": can't find $jarfile"
+    exit 1
+fi
+
+# By default, give decoder a max heap size of 1 gig. This can be overridden
+# by using a "-J" option (see below).
+defaultMx="-Xmx1024M"
+
+# The following will extract any initial parameters of the form
+# "-J<stuff>" from the command line and pass them to the Java
+# invocation (instead of to the decoder). This makes it possible for
+# you to add a command-line parameter such as "-JXmx256M" in your
+# scripts, for example. "java" (with no args) and "java -X" give a
+# summary of available options.
+
+javaOpts=""
+
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "x$1" : 'x-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    if expr "x${opt}" : "xXmx[0-9]" >/dev/null; then
+        defaultMx="no"
+    fi
+    shift
+done
+
+if [ "${defaultMx}" != "no" ]; then
+    javaOpts="${javaOpts} ${defaultMx}"
+fi
+
+if [ "$OSTYPE" = "cygwin" ]; then
+    # For Cygwin, convert the jarfile path into native Windows style.
+    jarpath=`cygpath -w "$libdir/$jarfile"`
+else
+    jarpath="$libdir/$jarfile"
+fi
+
+exec java $javaOpts -jar "$jarpath" "$@"
diff --git a/util/etc/manifest.txt b/util/etc/manifest.txt
new file mode 100644
index 0000000..84842ed
--- /dev/null
+++ b/util/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.launcher3.DecoderRing
diff --git a/src/com/android/launcher3/DrawableTileSource.java b/wallpaper_picker_src/com/android/launcher3/DrawableTileSource.java
similarity index 100%
rename from src/com/android/launcher3/DrawableTileSource.java
rename to wallpaper_picker_src/com/android/launcher3/DrawableTileSource.java
diff --git a/src/com/android/launcher3/LiveWallpaperListAdapter.java b/wallpaper_picker_src/com/android/launcher3/LiveWallpaperListAdapter.java
similarity index 100%
rename from src/com/android/launcher3/LiveWallpaperListAdapter.java
rename to wallpaper_picker_src/com/android/launcher3/LiveWallpaperListAdapter.java
diff --git a/src/com/android/launcher3/SavedWallpaperImages.java b/wallpaper_picker_src/com/android/launcher3/SavedWallpaperImages.java
similarity index 100%
rename from src/com/android/launcher3/SavedWallpaperImages.java
rename to wallpaper_picker_src/com/android/launcher3/SavedWallpaperImages.java
diff --git a/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/wallpaper_picker_src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
similarity index 100%
rename from src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
rename to wallpaper_picker_src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
diff --git a/src/com/android/launcher3/WallpaperRootView.java b/wallpaper_picker_src/com/android/launcher3/WallpaperRootView.java
similarity index 100%
rename from src/com/android/launcher3/WallpaperRootView.java
rename to wallpaper_picker_src/com/android/launcher3/WallpaperRootView.java