WallpaperCropActivity.java revision e8d1bf7a439450b9979701909164a6baffbe8bae
1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/*
2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2013 The Android Open Source Project
3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License.
6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at
7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software
11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and
14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License.
15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/* Copied from Launcher3 */
17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.wallpapercropper;
18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.app.ActionBar;
20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.app.Activity;
21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.app.WallpaperManager;
22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.Context;
23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.Intent;
24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.SharedPreferences;
25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.Configuration;
26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.res.Resources;
27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap;
28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap.CompressFormat;
29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.BitmapFactory;
30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.BitmapRegionDecoder;
31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas;
32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Matrix;
33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint;
34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Point;
35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Rect;
36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.RectF;
37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.net.Uri;
38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.AsyncTask;
39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Bundle;
40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.Log;
41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.Display;
42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.View;
43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.WindowManager;
44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.common.Utils;
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.photos.BitmapRegionTileSource;
47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.BufferedInputStream;
49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.ByteArrayInputStream;
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.ByteArrayOutputStream;
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.FileNotFoundException;
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.IOException;
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.InputStream;
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class WallpaperCropActivity extends Activity {
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String LOGTAG = "Launcher3.CropActivity";
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int DEFAULT_COMPRESS_QUALITY = 90;
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * The maximum bitmap size we allow to be returned through the intent.
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * have some overhead to hit so that we go way below the limit here to make
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * sure the intent stays below 1MB.We should consider just returning a byte
66e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * array instead of a Bitmap instance to avoid overhead.
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static final int MAX_BMAP_IN_INTENT = 750000;
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final float WALLPAPER_SCREENS_SPAN = 2f;
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected CropView mCropView;
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected Uri mUri;
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void onCreate(Bundle savedInstanceState) {
76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.onCreate(savedInstanceState);
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        init();
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void init() {
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        setContentView(R.layout.wallpaper_cropper);
82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mCropView = (CropView) findViewById(R.id.cropView);
84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Intent cropIntent = this.getIntent();
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Uri imageUri = cropIntent.getData();
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mCropView.setTouchEnabled(true);
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Action bar
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Show the custom action bar view
92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final ActionBar actionBar = getActionBar();
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        actionBar.getCustomView().setOnClickListener(
95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                new View.OnClickListener() {
96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    @Override
97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    public void onClick(View v) {
98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        boolean finishActivityWhenDone = true;
99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                });
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static String getSharedPreferencesKey() {
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return WallpaperCropActivity.class.getName();
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // As a ratio of screen height, the total distance we want the parallax effect to span
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // horizontally
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float aspectRatio = width / (float) height;
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We will use these two data points to extrapolate how much the wallpaper parallax effect
116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // to span (ie travel) at any aspect ratio:
117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float ASPECT_RATIO_PORTRAIT = 10/16f;
120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // To find out the desired width at different aspect ratios, we use the following two
124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // formulas, where the coefficient on x is the aspect ratio (width/height):
125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        //   (16/10)x + y = 1.5
126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        //   (10/16)x + y = 1.2
127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We solve for x and y and end up with a final formula:
128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float x =
129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return x * aspectRatio + y;
133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point minDims = new Point();
137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point maxDims = new Point();
138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int maxDim = Math.max(maxDims.x, maxDims.y);
141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int minDim = Math.min(minDims.x, minDims.y);
142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Point realSize = new Point();
145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            windowManager.getDefaultDisplay().getRealSize(realSize);
146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            maxDim = Math.max(realSize.x, realSize.y);
147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We need to ensure that there is enough extra space in the wallpaper
150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // for the intended
151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // parallax effects
152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int defaultWidth, defaultHeight;
153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isScreenLarge(res)) {
154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultHeight = maxDim;
156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultHeight = maxDim;
159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return new Point(defaultWidth, defaultHeight);
161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        BitmapCropTask cropTask = new BitmapCropTask(this,
166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                filePath, null, 0, 0, true, false, null);
167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Point bounds = cropTask.getImageBounds();
168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(bounds.x, bounds.y);
171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.setOnEndRunnable(onEndCrop);
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.setNoCrop(true);
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void cropImageAndSetWallpaper(
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Resources res, int resId, final boolean finishActivityWhenDone) {
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // crop this image and scale it down to the default wallpaper size for
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // this device
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point inSize = mCropView.getSourceDimensions();
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point outSize = getDefaultWallpaperSize(getResources(),
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                getWindowManager());
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF crop = getMaxCropRect(
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                inSize.x, inSize.y, outSize.x, outSize.y, false);
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Passing 0, 0 will cause launcher to revert to using the
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // default wallpaper size
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(0, 0);
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        BitmapCropTask cropTask = new BitmapCropTask(res, resId,
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                crop, outSize.x, outSize.y,
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                true, false, onEndCrop);
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static boolean isScreenLarge(Resources res) {
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Configuration config = res.getConfiguration();
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return config.smallestScreenWidthDp >= 720;
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void cropImageAndSetWallpaper(Uri uri,
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     // Get the crop
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point inSize = mCropView.getSourceDimensions();
217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point minDims = new Point();
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point maxDims = new Point();
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Display d = getWindowManager().getDefaultDisplay();
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        d.getCurrentSizeRange(minDims, maxDims);
222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point displaySize = new Point();
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        d.getSize(displaySize);
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int maxDim = Math.max(maxDims.x, maxDims.y);
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int minDim = Math.min(minDims.x, minDims.y);
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int defaultWidth;
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isScreenLarge(getResources())) {
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = (int) (maxDim *
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    wallpaperTravelToScreenWidthRatio(maxDim, minDim));
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = Math.max((int)
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean isPortrait = displaySize.x < displaySize.y;
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int portraitHeight;
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isPortrait) {
240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            portraitHeight = mCropView.getHeight();
241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // TODO: how to actually get the proper portrait height?
243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // This is not quite right:
244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            portraitHeight = Math.max(maxDims.x, maxDims.y);
245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (android.os.Build.VERSION.SDK_INT >=
247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Point realSize = new Point();
249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            d.getRealSize(realSize);
250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            portraitHeight = Math.max(realSize.x, realSize.y);
251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Get the crop
253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF cropRect = mCropView.getCrop();
254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float cropScale = mCropView.getWidth() / (float) cropRect.width();
255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // ADJUST CROP WIDTH
257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Extend the crop all the way to the right, for parallax
258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float extraSpaceToRight = inSize.x - cropRect.right;
259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Cap the amount of extra width
260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
261e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
262e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
263e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropRect.right += extraSpaceToRight;
264e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
265e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // ADJUST CROP HEIGHT
266e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isPortrait) {
267e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.bottom = cropRect.top + portraitHeight / cropScale;
268e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else { // LANDSCAPE
269e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float extraPortraitHeight =
270e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    portraitHeight / cropScale - cropRect.height();
271e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float expandHeight =
272e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
273e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            extraPortraitHeight / 2);
274e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.top -= expandHeight;
275e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.bottom += expandHeight;
276e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
277e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int outWidth = (int) Math.round(cropRect.width() * cropScale);
278e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int outHeight = (int) Math.round(cropRect.height() * cropScale);
279e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
280e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
281e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(outWidth, outHeight);
283e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
284e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
285e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        BitmapCropTask cropTask = new BitmapCropTask(uri,
290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                cropRect, outWidth, outHeight, true, false, onEndCrop);
291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (onBitmapCroppedHandler != null) {
292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public interface OnBitmapCroppedHandler {
298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void onBitmapCropped(byte[] imageBytes);
299e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
300e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
301e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
302e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Uri mInUri = null;
303e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Context mContext;
304e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String mInFilePath;
305e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        byte[] mInImageBytes;
306e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mInResId = 0;
307e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        InputStream mInStream;
308e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF mCropBounds = null;
309e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mOutWidth, mOutHeight;
310e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mRotation = 0; // for now
311e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        protected final WallpaperManager mWPManager;
312e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String mOutputFormat = "jpg"; // for now
313e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mSetWallpaper;
314e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mSaveCroppedBitmap;
315e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap mCroppedBitmap;
316e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable mOnEndRunnable;
317e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Resources mResources;
318e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        OnBitmapCroppedHandler mOnBitmapCroppedHandler;
319e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mNoCrop;
320e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
321e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(Context c, String filePath,
322e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                RectF cropBounds, int outWidth, int outHeight,
323e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
324e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mContext = c;
325e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInFilePath = filePath;
326e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mWPManager = WallpaperManager.getInstance(getApplicationContext());
327e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
328e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
329e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
330e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(byte[] imageBytes,
331e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                RectF cropBounds, int outWidth, int outHeight,
332e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
333e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInImageBytes = imageBytes;
334e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mWPManager = WallpaperManager.getInstance(getApplicationContext());
335e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
336e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
337e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
338e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(Uri inUri,
339e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                RectF cropBounds, int outWidth, int outHeight,
340e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
341e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInUri = inUri;
342e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mWPManager = WallpaperManager.getInstance(getApplicationContext());
343e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
344e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
345e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
346e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(Resources res, int inResId,
347e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                RectF cropBounds, int outWidth, int outHeight,
348e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
349e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInResId = inResId;
350e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mResources = res;
351e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mWPManager = WallpaperManager.getInstance(getApplicationContext());
352e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
353e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
354e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
355e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void init(RectF cropBounds, int outWidth, int outHeight,
356e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
357e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCropBounds = cropBounds;
358e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOutWidth = outWidth;
359e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOutHeight = outHeight;
360e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mSetWallpaper = setWallpaper;
361e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mSaveCroppedBitmap = saveCroppedBitmap;
362e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnEndRunnable = onEndRunnable;
363e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
364e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
365e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
366e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnBitmapCroppedHandler = handler;
367e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setNoCrop(boolean value) {
370e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mNoCrop = value;
371e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
372e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
373e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setOnEndRunnable(Runnable onEndRunnable) {
374e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnEndRunnable = onEndRunnable;
375e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
376e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Helper to setup input stream
378e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private void regenerateInputStream() {
379e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
381e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "image byte array given");
382e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
383e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Utils.closeSilently(mInStream);
384e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
385e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mInUri != null) {
386e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mInStream = new BufferedInputStream(
387e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                getContentResolver().openInputStream(mInUri));
388e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else if (mInFilePath != null) {
389e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mInStream = mContext.openFileInput(mInFilePath);
390e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else if (mInImageBytes != null) {
391e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mInStream = new BufferedInputStream(
392e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                new ByteArrayInputStream(mInImageBytes));
393e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else {
394e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mInStream = new BufferedInputStream(
395e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                mResources.openRawResource(mInResId));
396e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
397e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (FileNotFoundException e) {
398e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
399e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
400e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
401e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
402e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
403e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Point getImageBounds() {
404e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            regenerateInputStream();
405e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mInStream != null) {
406e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                BitmapFactory.Options options = new BitmapFactory.Options();
407e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                options.inJustDecodeBounds = true;
408e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                BitmapFactory.decodeStream(mInStream, null, options);
409e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (options.outWidth != 0 && options.outHeight != 0) {
410e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return new Point(options.outWidth, options.outHeight);
411e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
412e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
413e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return null;
414e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
415e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
416e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setCropBounds(RectF cropBounds) {
417e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCropBounds = cropBounds;
418e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
419e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
420e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Bitmap getCroppedBitmap() {
421e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mCroppedBitmap;
422e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
423e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean cropBitmap() {
424e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            boolean failure = false;
425e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
426e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            regenerateInputStream();
427e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
428e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mNoCrop && mInStream != null) {
429e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
430e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mWPManager.setStream(mInStream);
431e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (IOException e) {
432e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot write stream to wallpaper", e);
433e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
434e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
435e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (mOnEndRunnable != null) {
436e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mOnEndRunnable.run();
437e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
438e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return !failure;
439e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
440e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mInStream != null) {
441e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Find crop bounds (scaled to original image size)
442e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Rect roundedTrueCrop = new Rect();
443e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mCropBounds.roundOut(roundedTrueCrop);
444e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
445e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
446e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "crop has bad values for full size image");
447e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
448e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return false;
449e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
450e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
451e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // See how much we're reducing the size of the image
452e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
453e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        roundedTrueCrop.height() / mOutHeight);
454e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
455e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Attempt to open a region decoder
456e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                BitmapRegionDecoder decoder = null;
457e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
458e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    decoder = BitmapRegionDecoder.newInstance(mInStream, true);
459e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (IOException e) {
460e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
461e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
462e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
463e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Bitmap crop = null;
464e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (decoder != null) {
465e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // Do region decoding to get crop bitmap
466e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    BitmapFactory.Options options = new BitmapFactory.Options();
467e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (scaleDownSampleSize > 1) {
468e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        options.inSampleSize = scaleDownSampleSize;
469e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
470e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    crop = decoder.decodeRegion(roundedTrueCrop, options);
471e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    decoder.recycle();
472e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
473e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
474e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop == null) {
475e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // BitmapRegionDecoder has failed, try to crop in-memory
476e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    regenerateInputStream();
477e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap fullSize = null;
478e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mInStream != null) {
479e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        BitmapFactory.Options options = new BitmapFactory.Options();
480e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (scaleDownSampleSize > 1) {
481e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            options.inSampleSize = scaleDownSampleSize;
482e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
483e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        fullSize = BitmapFactory.decodeStream(mInStream, null, options);
484e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
485e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (fullSize != null) {
486e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
487e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                roundedTrueCrop.top, roundedTrueCrop.width(),
488e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                roundedTrueCrop.height());
489e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
490e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
491e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
492e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop == null) {
493e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
494e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
495e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return false;
496e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
497e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (mOutWidth > 0 && mOutHeight > 0) {
498e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Matrix m = new Matrix();
499e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
500e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mRotation > 0) {
501e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        m.setRotate(mRotation);
502e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        m.mapRect(cropRect);
503e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
504e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
505e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
506e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    m.preRotate(mRotation);
507e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
508e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            (int) returnRect.height(), Bitmap.Config.ARGB_8888);
509e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (tmp != null) {
510e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Canvas c = new Canvas(tmp);
511e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        c.drawBitmap(crop, m, new Paint());
512e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        crop = tmp;
513e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
514e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else if (mRotation > 0) {
515e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Matrix m = new Matrix();
516e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    m.setRotate(mRotation);
517e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
518e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            crop.getHeight(), m, true);
519e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (tmp != null) {
520e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        crop = tmp;
521e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
522e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
523e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
524e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (mSaveCroppedBitmap) {
525e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mCroppedBitmap = crop;
526e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
527e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
528e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Get output compression format
529e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                CompressFormat cf =
530e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
531e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
532e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Compress to byte array
533e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
534e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
535e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // If we need to set to the wallpaper, set it
536e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mSetWallpaper && mWPManager != null) {
537e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (mWPManager == null) {
538e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            Log.w(LOGTAG, "no wallpaper manager");
539e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            failure = true;
540e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        } else {
541e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            try {
542e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                byte[] outByteArray = tmpOut.toByteArray();
543e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                mWPManager.setStream(new ByteArrayInputStream(outByteArray));
544e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                if (mOnBitmapCroppedHandler != null) {
545e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                    mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
546e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                }
547e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            } catch (IOException e) {
548e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                Log.w(LOGTAG, "cannot write stream to wallpaper", e);
549e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                failure = true;
550e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            }
551e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
552e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
553e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mOnEndRunnable != null) {
554e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mOnEndRunnable.run();
555e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
556e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else {
557e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot compress bitmap");
558e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
559e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
560e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
561e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return !failure; // True if any of the operations failed
562e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
563e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
564e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
565e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        protected Boolean doInBackground(Void... params) {
566e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return cropBitmap();
567e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
568e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
569e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
570e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        protected void onPostExecute(Boolean result) {
571e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            setResult(Activity.RESULT_OK);
572e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            finish();
573e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
574e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
575e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
576e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void updateWallpaperDimensions(int width, int height) {
577e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String spKey = getSharedPreferencesKey();
578e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
579e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        SharedPreferences.Editor editor = sp.edit();
580e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (width != 0 && height != 0) {
581e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.putInt(WALLPAPER_WIDTH_KEY, width);
582e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.putInt(WALLPAPER_HEIGHT_KEY, height);
583e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
584e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.remove(WALLPAPER_WIDTH_KEY);
585e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.remove(WALLPAPER_HEIGHT_KEY);
586e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
587e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        editor.commit();
588e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
589e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        suggestWallpaperDimension(getResources(),
590e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                sp, getWindowManager(), WallpaperManager.getInstance(this));
591e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
592e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
593e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    static public void suggestWallpaperDimension(Resources res,
594e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final SharedPreferences sharedPrefs,
595e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            WindowManager windowManager,
596e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final WallpaperManager wallpaperManager) {
597e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Point defaultWallpaperSize =
598e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
599e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
600e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        new Thread("suggestWallpaperDimension") {
601e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
602e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // If we have saved a wallpaper width/height, use that instead
603e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
604e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
605e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
606e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
607e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }.start();
608e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
609e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
610e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
611e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static RectF getMaxCropRect(
612e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
613e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF cropRect = new RectF();
614e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Get a crop rect that will fit this
615e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
616e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.top = 0;
617e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.bottom = inHeight;
618e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
619e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.right = inWidth - cropRect.left;
620e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             if (leftAligned) {
621e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                 cropRect.right -= cropRect.left;
622e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                 cropRect.left = 0;
623e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             }
624e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
625e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.left = 0;
626e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.right = inWidth;
627e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
628e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.bottom = inHeight - cropRect.top;
629e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
630e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return cropRect;
631e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
632e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
633e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static CompressFormat convertExtensionToCompressFormat(String extension) {
634e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
635e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
636e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
637e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static String getFileExtension(String requestFormat) {
638e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String outputFormat = (requestFormat == null)
639e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? "jpg"
640e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : requestFormat;
641e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        outputFormat = outputFormat.toLowerCase();
642e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return (outputFormat.equals("png") || outputFormat.equals("gif"))
643e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? "png" // We don't support gif compression.
644e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : "jpg";
645e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
646e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka}
647