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