OSDN Git Service

Create a separate wallpaper crop activity
authorMichael Jurka <mikejurka@google.com>
Wed, 4 Sep 2013 12:42:52 +0000 (14:42 +0200)
committerMichael Jurka <mikejurka@google.com>
Thu, 5 Sep 2013 18:37:56 +0000 (20:37 +0200)
Change-Id: Ifb0a7dcb5a6e9ddd4f4bbccc793d9b4db1256cf2

AndroidManifest.xml
res/layout/wallpaper_cropper.xml [new file with mode: 0644]
res/values/strings.xml
src/com/android/launcher3/WallpaperCropActivity.java
src/com/android/launcher3/WallpaperPickerActivity.java

index 477c4e1..a91de65 100644 (file)
             android:finishOnCloseSystemDialogs="true"
             android:process=":wallpaper_chooser">
             <intent-filter>
-                <action android:name="android.intent.action.SET_WALLPAPER" />
+                <action android:name="com.android.launcher3.action.CROP_AND_SET_WALLPAPER" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="image/*" />
             </intent-filter>
         </activity>
 
+        <activity
+            android:name="com.android.launcher3.WallpaperCropActivity"
+            android:theme="@style/Theme.WallpaperPicker"
+            android:label="@string/pick_wallpaper"
+            android:icon="@mipmap/ic_launcher_wallpaper"
+            android:finishOnCloseSystemDialogs="true"
+            android:process=":wallpaper_chooser">
+            <intent-filter>
+                <action android:name="com.android.launcher3.action.CROP_AND_SET_WALLPAPER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
 
         <!-- Debugging tools -->
         <activity
diff --git a/res/layout/wallpaper_cropper.xml b/res/layout/wallpaper_cropper.xml
new file mode 100644 (file)
index 0000000..768500c
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/wallpaper_cropper"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <com.android.launcher3.CropView
+        android:id="@+id/cropView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <ProgressBar
+        android:id="@+id/loading"
+        style="@android:style/Widget.Holo.ProgressBar.Large"
+        android:visibility="invisible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:indeterminate="true"
+        android:indeterminateOnly="true"
+        android:background="@android:color/transparent" />
+</RelativeLayout>
index b860d42..b43f51b 100644 (file)
     <string name="uid_name">Android Core Apps</string>
     <!-- Default folder name -->
     <string name="folder_name"></string>
-    <!-- Title of dialog that appears after user selects Wallpaper from menu -->
-    <string name="chooser_wallpaper">Choose wallpaper from</string>
     <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper -->
     <string name="wallpaper_instructions">Set wallpaper</string>
     <!-- Label on button in Wallpaper Picker that launches Gallery app -->
     <string name="gallery">Gallery</string>
-    <!-- Option in "Select wallpaper from" dialog box -->
-    <string name="pick_wallpaper">Wallpapers</string>
     <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]-->
     <string name="activity_not_found">App isn\'t installed.</string>
     <!--  Labels for the tabs in the customize drawer -->
@@ -88,8 +84,6 @@ s -->
     <string name="group_shortcuts">Shortcuts</string>
     <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
     <string name="group_widgets">Widgets</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of apps that can set the wallpaper-->
-    <string name="group_wallpapers">Wallpapers</string>
     <!-- Error message when user has filled all their home screens -->
     <string name="completely_out_of_space">No more room on your Home screens.</string>
     <!-- Error message when user has filled a home screen -->
@@ -142,23 +136,6 @@ s -->
          be uninstalled. [CHAR_LIMIT=30] -->
     <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
 
-    <!-- Menus items: -->
-    <skip />
-    <!-- Verb, menu item used to add an item on the desktop -->
-    <string name="menu_add">Add</string>
-    <!-- Menu item used to manage installed applications -->
-    <string name="menu_manage_apps">Manage apps</string>
-    <!-- Noun, menu item used to set the desktop's wallpaper -->
-    <string name="menu_wallpaper">Wallpaper</string>
-    <!-- Verb, menu item used to initiate global search -->
-    <string name="menu_search">Search</string>
-    <!-- Noun, menu item used to bring down the notifications shade -->
-    <string name="menu_notifications">Notifications</string>
-    <!-- Noun, menu item used to show the system settings -->
-    <string name="menu_settings">System settings</string>
-    <!-- Noun, menu item used to show help. [CHAR_LIMIT=none] -->
-    <string name="menu_help">Help</string>
-
     <!-- URL pointing to help text. If empty, no link to help will be created [DO NOT TRANSLATE] -->
     <string name="help_url" translatable="false"></string>
 
index 3468f2f..6832b0c 100644 (file)
 
 package com.android.launcher3;
 
+import android.app.ActionBar;
 import android.app.Activity;
 import android.app.WallpaperManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -33,9 +35,14 @@ import android.graphics.Rect;
 import android.graphics.RectF;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Bundle;
 import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
 
 import com.android.gallery3d.common.Utils;
+import com.android.photos.BitmapRegionTileSource;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
@@ -44,7 +51,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 
-// LAUNCHER crop activity!
 public class WallpaperCropActivity extends Activity {
     private static final String LOGTAG = "Launcher3.CropActivity";
 
@@ -59,7 +65,201 @@ public class WallpaperCropActivity extends Activity {
      * array instead of a Bitmap instance to avoid overhead.
      */
     public static final int MAX_BMAP_IN_INTENT = 750000;
+    private static final float WALLPAPER_SCREENS_SPAN = 2f;
 
+    protected CropView mCropView;
+    protected Uri mUri;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        init();
+    }
+
+    protected void init() {
+        setContentView(R.layout.wallpaper_cropper);
+
+        mCropView = (CropView) findViewById(R.id.cropView);
+
+        Intent cropIntent = this.getIntent();
+        final Uri imageUri = cropIntent.getData();
+
+        mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+        mCropView.setTouchEnabled(true);
+        // Action bar
+        // Show the custom action bar view
+        final ActionBar actionBar = getActionBar();
+        actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
+        actionBar.getCustomView().setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        boolean finishActivityWhenDone = true;
+                        cropImageAndSetWallpaper(imageUri, finishActivityWhenDone);
+                    }
+                });
+    }
+
+    // As a ratio of screen height, the total distance we want the parallax effect to span
+    // horizontally
+    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
+        float aspectRatio = width / (float) height;
+
+        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+        // We will use these two data points to extrapolate how much the wallpaper parallax effect
+        // to span (ie travel) at any aspect ratio:
+
+        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+        final float ASPECT_RATIO_PORTRAIT = 10/16f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+        // To find out the desired width at different aspect ratios, we use the following two
+        // formulas, where the coefficient on x is the aspect ratio (width/height):
+        //   (16/10)x + y = 1.5
+        //   (10/16)x + y = 1.2
+        // We solve for x and y and end up with a final formula:
+        final float x =
+            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+        return x * aspectRatio + y;
+    }
+
+    static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+        Point minDims = new Point();
+        Point maxDims = new Point();
+        windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+        int maxDim = Math.max(maxDims.x, maxDims.y);
+        final int minDim = Math.min(minDims.x, minDims.y);
+
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            Point realSize = new Point();
+            windowManager.getDefaultDisplay().getRealSize(realSize);
+            maxDim = Math.max(realSize.x, realSize.y);
+        }
+
+        // We need to ensure that there is enough extra space in the wallpaper
+        // for the intended
+        // parallax effects
+        final int defaultWidth, defaultHeight;
+        if (LauncherAppState.isScreenLarge(res)) {
+            defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+            defaultHeight = maxDim;
+        } else {
+            defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+            defaultHeight = maxDim;
+        }
+        return new Point(defaultWidth, defaultHeight);
+    }
+
+    protected void cropImageAndSetWallpaper(Resources res,
+            int resId, final boolean finishActivityWhenDone) {
+        // crop this image and scale it down to the default wallpaper size for
+        // this device
+        Point inSize = mCropView.getSourceDimensions();
+        Point outSize = getDefaultWallpaperSize(getResources(),
+                getWindowManager());
+        RectF crop = getMaxCropRect(
+                inSize.x, inSize.y, outSize.x, outSize.y);
+        Runnable onEndCrop = new Runnable() {
+            public void run() {
+                // Passing 0, 0 will cause launcher to revert to using the
+                // default wallpaper size
+                updateWallpaperDimensions(0, 0);
+                if (finishActivityWhenDone) {
+                    setResult(Activity.RESULT_OK);
+                    finish();
+                }
+            }
+        };
+        BitmapCropTask cropTask = new BitmapCropTask(res, resId,
+                crop, outSize.x, outSize.y,
+                true, false, onEndCrop);
+        cropTask.execute();
+    }
+
+    protected void cropImageAndSetWallpaper(Uri uri, final boolean finishActivityWhenDone) {
+     // Get the crop
+        Point inSize = mCropView.getSourceDimensions();
+
+        Point minDims = new Point();
+        Point maxDims = new Point();
+        Display d = getWindowManager().getDefaultDisplay();
+        d.getCurrentSizeRange(minDims, maxDims);
+
+        Point displaySize = new Point();
+        d.getSize(displaySize);
+
+        int maxDim = Math.max(maxDims.x, maxDims.y);
+        final int minDim = Math.min(minDims.x, minDims.y);
+        int defaultWidth;
+        if (LauncherAppState.isScreenLarge(getResources())) {
+            defaultWidth = (int) (maxDim *
+                    wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+        } else {
+            defaultWidth = Math.max((int)
+                    (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+        }
+
+        boolean isPortrait = displaySize.x < displaySize.y;
+        int portraitHeight;
+        if (isPortrait) {
+            portraitHeight = mCropView.getHeight();
+        } else {
+            // TODO: how to actually get the proper portrait height?
+            // This is not quite right:
+            portraitHeight = Math.max(maxDims.x, maxDims.y);
+        }
+        if (android.os.Build.VERSION.SDK_INT >=
+                android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            Point realSize = new Point();
+            d.getRealSize(realSize);
+            portraitHeight = Math.max(realSize.x, realSize.y);
+        }
+        // Get the crop
+        RectF cropRect = mCropView.getCrop();
+        float cropScale = mCropView.getWidth() / (float) cropRect.width();
+
+        // ADJUST CROP WIDTH
+        // Extend the crop all the way to the right, for parallax
+        float extraSpaceToRight = inSize.x - cropRect.right;
+        // Cap the amount of extra width
+        float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
+        extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
+
+        cropRect.right += extraSpaceToRight;
+
+        // ADJUST CROP HEIGHT
+        if (isPortrait) {
+            cropRect.bottom = cropRect.top + portraitHeight / cropScale;
+        } else { // LANDSCAPE
+            float extraPortraitHeight =
+                    portraitHeight / cropScale - cropRect.height();
+            float expandHeight =
+                    Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+                            extraPortraitHeight / 2);
+            cropRect.top -= expandHeight;
+            cropRect.bottom += expandHeight;
+        }
+        final int outWidth = (int) Math.round(cropRect.width() * cropScale);
+        final int outHeight = (int) Math.round(cropRect.height() * cropScale);
+
+        Runnable onEndCrop = new Runnable() {
+            public void run() {
+                updateWallpaperDimensions(outWidth, outHeight);
+                if (finishActivityWhenDone) {
+                    setResult(Activity.RESULT_OK);
+                    finish();
+                }
+            }
+        };
+        BitmapCropTask cropTask = new BitmapCropTask(uri,
+                cropRect, outWidth, outHeight, true, false, onEndCrop);
+        cropTask.execute();
+    }
 
     protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
         Uri mInUri = null;
@@ -294,10 +494,45 @@ public class WallpaperCropActivity extends Activity {
         }
         editor.commit();
 
-        WallpaperPickerActivity.suggestWallpaperDimension(getResources(),
+        suggestWallpaperDimension(getResources(),
                 sp, getWindowManager(), WallpaperManager.getInstance(this));
     }
 
+    static public void suggestWallpaperDimension(Resources res,
+            final SharedPreferences sharedPrefs,
+            WindowManager windowManager,
+            final WallpaperManager wallpaperManager) {
+        final Point defaultWallpaperSize =
+                WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+
+        new Thread("suggestWallpaperDimension") {
+            public void run() {
+                // If we have saved a wallpaper width/height, use that instead
+                int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
+                int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
+                wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
+            }
+        }.start();
+    }
+
+
+    protected static RectF getMaxCropRect(int inWidth, int inHeight, int outWidth, int outHeight) {
+        RectF cropRect = new RectF();
+        // Get a crop rect that will fit this
+        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+             cropRect.top = 0;
+             cropRect.bottom = inHeight;
+             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+             cropRect.right = inWidth - cropRect.left;
+        } else {
+            cropRect.left = 0;
+            cropRect.right = inWidth;
+            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+            cropRect.bottom = inHeight - cropRect.top;
+        }
+        return cropRect;
+    }
+
     protected static CompressFormat convertExtensionToCompressFormat(String extension) {
         return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
     }
index b7226f6..674c597 100644 (file)
@@ -18,10 +18,8 @@ package com.android.launcher3;
 
 import android.app.ActionBar;
 import android.app.Activity;
-import android.app.WallpaperManager;
 import android.content.ComponentName;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -36,7 +34,6 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.util.Pair;
-import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -64,7 +61,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
 
     private static final int IMAGE_PICK = 5;
     private static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
-    private static final float WALLPAPER_SCREENS_SPAN = 2f;
 
     private ArrayList<Drawable> mThumbs;
     private ArrayList<Integer> mImages;
@@ -73,6 +69,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
     private View mSelectedThumb;
     private CropView mCropView;
     private boolean mIgnoreNextTap;
+    private OnClickListener mThumbnailOnClickListener;
 
     private static class ThumbnailMetaData {
         public boolean mLaunchesGallery;
@@ -80,106 +77,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
         public int mWallpaperResId;
     }
 
-    private OnClickListener mThumbnailOnClickListener = new OnClickListener() {
-        public void onClick(View v) {
-            if (mSelectedThumb != null) {
-                mSelectedThumb.setSelected(false);
-            }
-
-            ThumbnailMetaData meta = (ThumbnailMetaData) v.getTag();
-
-            if (!meta.mLaunchesGallery) {
-                mSelectedThumb = v;
-                v.setSelected(true);
-            }
-
-            if (meta.mLaunchesGallery) {
-                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-                intent.setType("image/*");
-                Utilities.startActivityForResultSafely(
-                        WallpaperPickerActivity.this, intent, IMAGE_PICK);
-            } else if (meta.mGalleryImageUri != null) {
-                mCropView.setTileSource(new BitmapRegionTileSource(WallpaperPickerActivity.this,
-                        meta.mGalleryImageUri, 1024, 0), null);
-                mCropView.setTouchEnabled(true);
-            } else {
-                BitmapRegionTileSource source = new BitmapRegionTileSource(mWallpaperResources,
-                        WallpaperPickerActivity.this, meta.mWallpaperResId, 1024, 0);
-                mCropView.setTileSource(source, null);
-                Point wallpaperSize = getDefaultWallpaperSize(getResources(), getWindowManager());
-                RectF crop = getMaxCropRect(source.getImageWidth(), source.getImageHeight(),
-                        wallpaperSize.x, wallpaperSize.y);
-                mCropView.setScale(wallpaperSize.x / crop.width());
-                mCropView.setTouchEnabled(false);
-            }
-        }
-    };
-
-    private RectF getMaxCropRect(int inWidth, int inHeight, int outWidth, int outHeight) {
-        RectF cropRect = new RectF();
-        // Get a crop rect that will fit this
-        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
-             cropRect.top = 0;
-             cropRect.bottom = inHeight;
-             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
-             cropRect.right = inWidth - cropRect.left;
-        } else {
-            cropRect.left = 0;
-            cropRect.right = inWidth;
-            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
-            cropRect.bottom = inHeight - cropRect.top;
-        }
-        return cropRect;
-    }
-
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == IMAGE_PICK && resultCode == RESULT_OK) {
-            Uri uri = data.getData();
-
-            // Add a tile for the image picked from Gallery
-            LinearLayout wallpapers = (LinearLayout) findViewById(R.id.wallpaper_list);
-            FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater().
-                    inflate(R.layout.wallpaper_picker_item, wallpapers, false);
-            setWallpaperItemPaddingToZero(pickedImageThumbnail);
-
-            // Load the thumbnail
-            ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
-
-            Resources res = getResources();
-            int width = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth);
-            int height = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight);
-
-            BitmapCropTask cropTask =
-                    new BitmapCropTask(uri, null, width, height, false, true, null);
-            Point bounds = cropTask.getImageBounds();
-
-            RectF cropRect = getMaxCropRect(bounds.x, bounds.y, width, height);
-            cropTask.setCropBounds(cropRect);
-
-            if (cropTask.cropBitmap()) {
-                image.setImageBitmap(cropTask.getCroppedBitmap());
-                Drawable thumbDrawable = image.getDrawable();
-                thumbDrawable.setDither(true);
-            } else {
-                Log.e(TAG, "Error loading thumbnail for uri=" + uri);
-            }
-            wallpapers.addView(pickedImageThumbnail, 0);
-
-            ThumbnailMetaData meta = new ThumbnailMetaData();
-            meta.mGalleryImageUri = uri;
-            pickedImageThumbnail.setTag(meta);
-            pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener);
-            mThumbnailOnClickListener.onClick(pickedImageThumbnail);
-        } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY) {
-            // No result code is returned; just return
-            setResult(RESULT_OK);
-            finish();
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
+    protected void init() {
         setContentView(R.layout.wallpaper_picker);
 
         mCropView = (CropView) findViewById(R.id.cropView);
@@ -212,6 +111,43 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
             }
         });
 
+        mThumbnailOnClickListener = new OnClickListener() {
+            public void onClick(View v) {
+                if (mSelectedThumb != null) {
+                    mSelectedThumb.setSelected(false);
+                }
+
+                ThumbnailMetaData meta = (ThumbnailMetaData) v.getTag();
+
+                if (!meta.mLaunchesGallery) {
+                    mSelectedThumb = v;
+                    v.setSelected(true);
+                }
+
+                if (meta.mLaunchesGallery) {
+                    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                    intent.setType("image/*");
+                    Utilities.startActivityForResultSafely(
+                            WallpaperPickerActivity.this, intent, IMAGE_PICK);
+                } else if (meta.mGalleryImageUri != null) {
+                    mCropView.setTileSource(new BitmapRegionTileSource(WallpaperPickerActivity.this,
+                            meta.mGalleryImageUri, 1024, 0), null);
+                    mCropView.setTouchEnabled(true);
+                } else {
+                    BitmapRegionTileSource source = new BitmapRegionTileSource(mWallpaperResources,
+                            WallpaperPickerActivity.this, meta.mWallpaperResId, 1024, 0);
+                    mCropView.setTileSource(source, null);
+                    Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
+                            getResources(), getWindowManager());
+                    RectF crop = WallpaperCropActivity.getMaxCropRect(
+                            source.getImageWidth(), source.getImageHeight(),
+                            wallpaperSize.x, wallpaperSize.y);
+                    mCropView.setScale(wallpaperSize.x / crop.width());
+                    mCropView.setTouchEnabled(false);
+                }
+            }
+        };
+
         // Populate the built-in wallpapers
         findWallpapers();
 
@@ -256,105 +192,63 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
                         if (meta.mLaunchesGallery) {
                             // shouldn't be selected, but do nothing
                         } else if (meta.mGalleryImageUri != null) {
-                            // Get the crop
-                            Point inSize = mCropView.getSourceDimensions();
-
-                            Point minDims = new Point();
-                            Point maxDims = new Point();
-                            Display d = getWindowManager().getDefaultDisplay();
-                            d.getCurrentSizeRange(minDims, maxDims);
-
-                            Point displaySize = new Point();
-                            d.getSize(displaySize);
-
-                            int maxDim = Math.max(maxDims.x, maxDims.y);
-                            final int minDim = Math.min(minDims.x, minDims.y);
-                            int defaultWidth;
-                            if (LauncherAppState.isScreenLarge(getResources())) {
-                                defaultWidth = (int) (maxDim *
-                                        wallpaperTravelToScreenWidthRatio(maxDim, minDim));
-                            } else {
-                                defaultWidth = Math.max((int)
-                                        (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
-                            }
-
-                            boolean isPortrait = displaySize.x < displaySize.y;
-                            int portraitHeight;
-                            if (isPortrait) {
-                                portraitHeight = mCropView.getHeight();
-                            } else {
-                                // TODO: how to actually get the proper portrait height?
-                                // This is not quite right:
-                                portraitHeight = Math.max(maxDims.x, maxDims.y);
-                            }
-                            if (android.os.Build.VERSION.SDK_INT >=
-                                    android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                                Point realSize = new Point();
-                                d.getRealSize(realSize);
-                                portraitHeight = Math.max(realSize.x, realSize.y);
-                            }
-                            // Get the crop
-                            RectF cropRect = mCropView.getCrop();
-                            float cropScale = mCropView.getWidth() / (float) cropRect.width();
-
-                            // ADJUST CROP WIDTH
-                            // Extend the crop all the way to the right, for parallax
-                            float extraSpaceToRight = inSize.x - cropRect.right;
-                            // Cap the amount of extra width
-                            float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
-                            extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
-
-                            cropRect.right += extraSpaceToRight;
-
-                            // ADJUST CROP HEIGHT
-                            if (isPortrait) {
-                                cropRect.bottom = cropRect.top + portraitHeight / cropScale;
-                            } else { // LANDSCAPE
-                                float extraPortraitHeight =
-                                        portraitHeight / cropScale - cropRect.height();
-                                float expandHeight =
-                                        Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
-                                                extraPortraitHeight / 2);
-                                cropRect.top -= expandHeight;
-                                cropRect.bottom += expandHeight;
-                            }
-                            final int outWidth = (int) Math.round(cropRect.width() * cropScale);
-                            final int outHeight = (int) Math.round(cropRect.height() * cropScale);
-
-                            Runnable onEndCrop = new Runnable() {
-                                public void run() {
-                                    updateWallpaperDimensions(outWidth, outHeight);
-                                }
-                            };
-                            BitmapCropTask cropTask = new BitmapCropTask(meta.mGalleryImageUri,
-                                    cropRect, outWidth, outHeight, true, false, onEndCrop);
-                            cropTask.execute();
+                            boolean finishActivityWhenDone = true;
+                            cropImageAndSetWallpaper(meta.mGalleryImageUri, finishActivityWhenDone);
                         } else if (meta.mWallpaperResId != 0) {
-                            // crop this image and scale it down to the default wallpaper size for
-                            // this device
-                            Point inSize = mCropView.getSourceDimensions();
-                            Point outSize = getDefaultWallpaperSize(getResources(),
-                                    getWindowManager());
-                            RectF crop = getMaxCropRect(
-                                    inSize.x, inSize.y, outSize.x, outSize.y);
-                            Runnable onEndCrop = new Runnable() {
-                                public void run() {
-                                    // Passing 0, 0 will cause launcher to revert to using the
-                                    // default wallpaper size
-                                    updateWallpaperDimensions(0, 0);
-                                }
-                            };
-                            BitmapCropTask cropTask = new BitmapCropTask(mWallpaperResources,
-                                    meta.mWallpaperResId, crop, outSize.x, outSize.y,
-                                    true, false, onEndCrop);
-                            cropTask.execute();
-                            setResult(Activity.RESULT_OK);
-                            finish();
+                            boolean finishActivityWhenDone = true;
+                            cropImageAndSetWallpaper(mWallpaperResources,
+                                    meta.mWallpaperResId, finishActivityWhenDone);
                         }
                     }
                 });
     }
 
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == IMAGE_PICK && resultCode == RESULT_OK) {
+            Uri uri = data.getData();
+
+            // Add a tile for the image picked from Gallery
+            LinearLayout wallpapers = (LinearLayout) findViewById(R.id.wallpaper_list);
+            FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater().
+                    inflate(R.layout.wallpaper_picker_item, wallpapers, false);
+            setWallpaperItemPaddingToZero(pickedImageThumbnail);
+
+            // Load the thumbnail
+            ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
+
+            Resources res = getResources();
+            int width = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth);
+            int height = res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight);
+
+            BitmapCropTask cropTask =
+                    new BitmapCropTask(uri, null, width, height, false, true, null);
+            Point bounds = cropTask.getImageBounds();
+
+            RectF cropRect = WallpaperCropActivity.getMaxCropRect(
+                    bounds.x, bounds.y, width, height);
+            cropTask.setCropBounds(cropRect);
+
+            if (cropTask.cropBitmap()) {
+                image.setImageBitmap(cropTask.getCroppedBitmap());
+                Drawable thumbDrawable = image.getDrawable();
+                thumbDrawable.setDither(true);
+            } else {
+                Log.e(TAG, "Error loading thumbnail for uri=" + uri);
+            }
+            wallpapers.addView(pickedImageThumbnail, 0);
+
+            ThumbnailMetaData meta = new ThumbnailMetaData();
+            meta.mGalleryImageUri = uri;
+            pickedImageThumbnail.setTag(meta);
+            pickedImageThumbnail.setOnClickListener(mThumbnailOnClickListener);
+            mThumbnailOnClickListener.onClick(pickedImageThumbnail);
+        } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY) {
+            // No result code is returned; just return
+            setResult(RESULT_OK);
+            finish();
+        }
+    }
+
     private static void setWallpaperItemPaddingToZero(FrameLayout frameLayout) {
         frameLayout.setPadding(0, 0, 0, 0);
         frameLayout.setForeground(new ZeroPaddingDrawable(frameLayout.getForeground()));
@@ -466,77 +360,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
         }
     }
 
-    // As a ratio of screen height, the total distance we want the parallax effect to span
-    // horizontally
-    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
-        float aspectRatio = width / (float) height;
-
-        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
-        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
-        // We will use these two data points to extrapolate how much the wallpaper parallax effect
-        // to span (ie travel) at any aspect ratio:
-
-        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
-        final float ASPECT_RATIO_PORTRAIT = 10/16f;
-        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
-        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
-
-        // To find out the desired width at different aspect ratios, we use the following two
-        // formulas, where the coefficient on x is the aspect ratio (width/height):
-        //   (16/10)x + y = 1.5
-        //   (10/16)x + y = 1.2
-        // We solve for x and y and end up with a final formula:
-        final float x =
-            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
-            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
-        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
-        return x * aspectRatio + y;
-    }
-
-    static private Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
-        Point minDims = new Point();
-        Point maxDims = new Point();
-        windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
-
-        int maxDim = Math.max(maxDims.x, maxDims.y);
-        final int minDim = Math.min(minDims.x, minDims.y);
-
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            Point realSize = new Point();
-            windowManager.getDefaultDisplay().getRealSize(realSize);
-            maxDim = Math.max(realSize.x, realSize.y);
-        }
-
-        // We need to ensure that there is enough extra space in the wallpaper
-        // for the intended
-        // parallax effects
-        final int defaultWidth, defaultHeight;
-        if (LauncherAppState.isScreenLarge(res)) {
-            defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
-            defaultHeight = maxDim;
-        } else {
-            defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
-            defaultHeight = maxDim;
-        }
-        return new Point(defaultWidth, defaultHeight);
-    }
-
-    static public void suggestWallpaperDimension(Resources res,
-            final SharedPreferences sharedPrefs,
-            WindowManager windowManager,
-            final WallpaperManager wallpaperManager) {
-        final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager);
-
-        new Thread("suggestWallpaperDimension") {
-            public void run() {
-                // If we have saved a wallpaper width/height, use that instead
-                int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
-                int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
-                wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
-            }
-        }.start();
-    }
-
     static class ZeroPaddingDrawable extends LevelListDrawable {
         public ZeroPaddingDrawable(Drawable d) {
             super();