WallpaperCropActivity.java revision 7718fc1291c73576417f0c25d88f5105f7ae7365
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;
447b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkaimport android.widget.Toast;
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.common.Utils;
4769784065ea78550944b7eddb559c0dac952e20e8Michael Jurkaimport com.android.gallery3d.exif.ExifInterface;
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.photos.BitmapRegionTileSource;
497b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurkaimport com.android.photos.BitmapRegionTileSource.BitmapSource;
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.BufferedInputStream;
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.ByteArrayInputStream;
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.ByteArrayOutputStream;
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.FileNotFoundException;
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.IOException;
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.io.InputStream;
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class WallpaperCropActivity extends Activity {
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String LOGTAG = "Launcher3.CropActivity";
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int DEFAULT_COMPRESS_QUALITY = 90;
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * The maximum bitmap size we allow to be returned through the intent.
66e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * have some overhead to hit so that we go way below the limit here to make
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * sure the intent stays below 1MB.We should consider just returning a byte
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * array instead of a Bitmap instance to avoid overhead.
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static final int MAX_BMAP_IN_INTENT = 750000;
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final float WALLPAPER_SCREENS_SPAN = 2f;
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected CropView mCropView;
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected Uri mUri;
76ba126c09a5c00cb0a96da6ece0b4ab4d7ed2d8cbSelim Cinek    private View mSetWallpaperButton;
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void onCreate(Bundle savedInstanceState) {
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.onCreate(savedInstanceState);
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        init();
82e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        if (!enableRotation()) {
83e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
84e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        }
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void init() {
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        setContentView(R.layout.wallpaper_cropper);
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mCropView = (CropView) findViewById(R.id.cropView);
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
9269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        Intent cropIntent = getIntent();
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Uri imageUri = cropIntent.getData();
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
9569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        if (imageUri == null) {
9669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity");
9769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            finish();
9869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            return;
9969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        }
10069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Action bar
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Show the custom action bar view
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final ActionBar actionBar = getActionBar();
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        actionBar.getCustomView().setOnClickListener(
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                new View.OnClickListener() {
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    @Override
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    public void onClick(View v) {
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        boolean finishActivityWhenDone = true;
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                });
113ba126c09a5c00cb0a96da6ece0b4ab4d7ed2d8cbSelim Cinek        mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
1145271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka
1155271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        // Load image in background
1167b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka        final BitmapRegionTileSource.UriBitmapSource bitmapSource =
1177b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024);
118ba126c09a5c00cb0a96da6ece0b4ab4d7ed2d8cbSelim Cinek        mSetWallpaperButton.setVisibility(View.INVISIBLE);
1197b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka        Runnable onLoad = new Runnable() {
1207b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            public void run() {
1217b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) {
1227b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    Toast.makeText(WallpaperCropActivity.this,
1237b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                            getString(R.string.wallpaper_load_fail),
1247b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                            Toast.LENGTH_LONG).show();
1257b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    finish();
126ba126c09a5c00cb0a96da6ece0b4ab4d7ed2d8cbSelim Cinek                } else {
127ba126c09a5c00cb0a96da6ece0b4ab4d7ed2d8cbSelim Cinek                    mSetWallpaperButton.setVisibility(View.VISIBLE);
1287b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                }
1297b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            }
1307b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka        };
1317b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka        setCropViewTileSource(bitmapSource, true, false, onLoad);
1325271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka    }
1335271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka
1347b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka    public void setCropViewTileSource(
1357b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled,
1367b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            final boolean moveToLeft, final Runnable postExecute) {
1375271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        final Context context = WallpaperCropActivity.this;
1385271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        final View progressView = findViewById(R.id.loading);
1395271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() {
1405271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            protected Void doInBackground(Void...args) {
1415271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                if (!isCancelled()) {
1425271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                    bitmapSource.loadInBackground();
1435271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                }
1445271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                return null;
1455271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            }
1465271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            protected void onPostExecute(Void arg) {
1475271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                if (!isCancelled()) {
1485271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                    progressView.setVisibility(View.INVISIBLE);
1497b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
1507b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        mCropView.setTileSource(
1517b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                                new BitmapRegionTileSource(context, bitmapSource), null);
1527b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        mCropView.setTouchEnabled(touchEnabled);
1537b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        if (moveToLeft) {
1547b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                            mCropView.moveToLeft();
1557b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        }
1565271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                    }
1575271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                }
1587b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                if (postExecute != null) {
1597b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    postExecute.run();
1607b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                }
1615271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            }
1625271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        };
1635271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        // We don't want to show the spinner every time we load an image, because that would be
1645271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        // annoying; instead, only start showing the spinner if loading the image has taken
1655271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        // longer than 1 sec (ie 1000 ms)
1665271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        progressView.postDelayed(new Runnable() {
1675271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            public void run() {
1685271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                if (loadBitmapTask.getStatus() != AsyncTask.Status.FINISHED) {
1695271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                    progressView.setVisibility(View.VISIBLE);
1705271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka                }
1715271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka            }
1725271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        }, 1000);
1735271ea16c1989f99c0db7ab80b2b321441f60023Michael Jurka        loadBitmapTask.execute();
174e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka    }
175e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka
176e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka    public boolean enableRotation() {
177e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        return getResources().getBoolean(R.bool.allow_rotation);
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static String getSharedPreferencesKey() {
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return WallpaperCropActivity.class.getName();
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // As a ratio of screen height, the total distance we want the parallax effect to span
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // horizontally
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float aspectRatio = width / (float) height;
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We will use these two data points to extrapolate how much the wallpaper parallax effect
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // to span (ie travel) at any aspect ratio:
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float ASPECT_RATIO_PORTRAIT = 10/16f;
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // To find out the desired width at different aspect ratios, we use the following two
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // formulas, where the coefficient on x is the aspect ratio (width/height):
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        //   (16/10)x + y = 1.5
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        //   (10/16)x + y = 1.2
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We solve for x and y and end up with a final formula:
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float x =
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return x * aspectRatio + y;
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point minDims = new Point();
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point maxDims = new Point();
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int maxDim = Math.max(maxDims.x, maxDims.y);
2178b4836085b928f0ada3b3e6e1d1fd0530ffd6d57Michael Jurka        int minDim = Math.max(minDims.x, minDims.y);
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Point realSize = new Point();
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            windowManager.getDefaultDisplay().getRealSize(realSize);
222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            maxDim = Math.max(realSize.x, realSize.y);
2238b4836085b928f0ada3b3e6e1d1fd0530ffd6d57Michael Jurka            minDim = Math.min(realSize.x, realSize.y);
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // We need to ensure that there is enough extra space in the wallpaper
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // for the intended
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // parallax effects
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int defaultWidth, defaultHeight;
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isScreenLarge(res)) {
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultHeight = maxDim;
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            defaultHeight = maxDim;
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return new Point(defaultWidth, defaultHeight);
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
24069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    public static int getRotationFromExif(String path) {
24169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        return getRotationFromExifHelper(path, null, 0, null, null);
24269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    }
24369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
24469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    public static int getRotationFromExif(Context context, Uri uri) {
24569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        return getRotationFromExifHelper(null, null, 0, context, uri);
24669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    }
24769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
24869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    public static int getRotationFromExif(Resources res, int resId) {
24969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        return getRotationFromExifHelper(null, res, resId, null, null);
25069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    }
25169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
25269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    private static int getRotationFromExifHelper(
25369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            String path, Resources res, int resId, Context context, Uri uri) {
25469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        ExifInterface ei = new ExifInterface();
255b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka        InputStream is = null;
256b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka        BufferedInputStream bis = null;
25769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        try {
25869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            if (path != null) {
25969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                ei.readExif(path);
26069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            } else if (uri != null) {
261b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                is = context.getContentResolver().openInputStream(uri);
262b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                bis = new BufferedInputStream(is);
26369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                ei.readExif(bis);
26469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            } else {
265b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                is = res.openRawResource(resId);
266b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                bis = new BufferedInputStream(is);
26769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                ei.readExif(bis);
26869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            }
26969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
27069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            if (ori != null) {
27169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                return ExifInterface.getRotationForOrientationValue(ori.shortValue());
27269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            }
27369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        } catch (IOException e) {
27469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            Log.w(LOGTAG, "Getting exif data failed", e);
275b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka        } finally {
276b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka            Utils.closeSilently(bis);
277b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka            Utils.closeSilently(is);
27869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        }
27969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        return 0;
28069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka    }
28169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
28369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        int rotation = getRotationFromExif(filePath);
28469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        BitmapCropTask cropTask = new BitmapCropTask(
28569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                this, filePath, null, rotation, 0, 0, true, false, null);
286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final Point bounds = cropTask.getImageBounds();
287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(bounds.x, bounds.y);
290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.setOnEndRunnable(onEndCrop);
297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.setNoCrop(true);
298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
299e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
300e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
301e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void cropImageAndSetWallpaper(
302e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Resources res, int resId, final boolean finishActivityWhenDone) {
303e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // crop this image and scale it down to the default wallpaper size for
304e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // this device
30569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        int rotation = getRotationFromExif(res, resId);
306e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point inSize = mCropView.getSourceDimensions();
307e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point outSize = getDefaultWallpaperSize(getResources(),
308e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                getWindowManager());
309e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF crop = getMaxCropRect(
310e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                inSize.x, inSize.y, outSize.x, outSize.y, false);
311e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
312e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
313e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Passing 0, 0 will cause launcher to revert to using the
314e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // default wallpaper size
315e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(0, 0);
316e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
317e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
318e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
319e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
320e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
321e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
322e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
32369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
324e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
325e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
326e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
327e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static boolean isScreenLarge(Resources res) {
328e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Configuration config = res.getConfiguration();
329e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return config.smallestScreenWidthDp >= 720;
330e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
331e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
332e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void cropImageAndSetWallpaper(Uri uri,
333e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
334929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
335e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        // Get the crop
336e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
337e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka
338e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Display d = getWindowManager().getDefaultDisplay();
339e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
340e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Point displaySize = new Point();
341e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        d.getSize(displaySize);
342e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean isPortrait = displaySize.x < displaySize.y;
343eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka
344eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka        Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
345eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka                getWindowManager());
346e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Get the crop
347e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF cropRect = mCropView.getCrop();
348eb95e74e21a0e910704ca2fd67e074ab640bfba3Selim Cinek
349c41853cee89b391cd2d4d93205ea69c746ccfa4cSelim Cinek        Point inSize = mCropView.getSourceDimensions();
350c41853cee89b391cd2d4d93205ea69c746ccfa4cSelim Cinek
35169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        int cropRotation = mCropView.getImageRotation();
352e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        float cropScale = mCropView.getWidth() / (float) cropRect.width();
353e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
35469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        Matrix rotateMatrix = new Matrix();
35569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        rotateMatrix.setRotate(cropRotation);
35669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        float[] rotatedInSize = new float[] { inSize.x, inSize.y };
35769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        rotateMatrix.mapPoints(rotatedInSize);
35869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        rotatedInSize[0] = Math.abs(rotatedInSize[0]);
35969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        rotatedInSize[1] = Math.abs(rotatedInSize[1]);
36069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
3617718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        // Due to rounding errors in the cropview renderer the edges can be slightly offset
3627718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        // therefore we ensure that the boundaries are sanely defined
3637718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        cropRect.left = Math.max(0, cropRect.left);
3647718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        cropRect.right = Math.min(rotatedInSize[0], cropRect.right);
3657718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        cropRect.top = Math.max(0, cropRect.top);
3667718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek        cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom);
3677718fc1291c73576417f0c25d88f5105f7ae7365Selim Cinek
368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // ADJUST CROP WIDTH
369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Extend the crop all the way to the right, for parallax
370e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        // (or all the way to the left, in RTL)
371929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        float extraSpace;
372929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        if (centerCrop) {
373929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            extraSpace = 2f * Math.min(rotatedInSize[0] - cropRect.right, cropRect.left);
374929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        } else {
375929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
376929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        }
377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Cap the amount of extra width
378eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka        float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width();
379e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        extraSpace = Math.min(extraSpace, maxExtraSpace);
380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
381929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka        if (centerCrop) {
382929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            cropRect.left -= extraSpace / 2f;
383929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            cropRect.right += extraSpace / 2f;
384e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        } else {
385929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            if (ltr) {
386929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka                cropRect.right += extraSpace;
387929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            } else {
388929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka                cropRect.left -= extraSpace;
389929e75e8d0c258ca134093413ed0d8ffb3ead1d4Michael Jurka            }
390e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        }
391e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
392e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // ADJUST CROP HEIGHT
393e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (isPortrait) {
394eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka            cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale;
395e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else { // LANDSCAPE
396e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float extraPortraitHeight =
397eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka                    defaultWallpaperSize.y / cropScale - cropRect.height();
398e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float expandHeight =
39969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
400e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            extraPortraitHeight / 2);
401e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.top -= expandHeight;
402e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.bottom += expandHeight;
403e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
404e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int outWidth = (int) Math.round(cropRect.width() * cropScale);
405e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        final int outHeight = (int) Math.round(cropRect.height() * cropScale);
406e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
407e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable onEndCrop = new Runnable() {
408e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            public void run() {
409e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                updateWallpaperDimensions(outWidth, outHeight);
410e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (finishActivityWhenDone) {
411e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    setResult(Activity.RESULT_OK);
412e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    finish();
413e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
414e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
415e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
416e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        BitmapCropTask cropTask = new BitmapCropTask(this, uri,
41769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
418e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (onBitmapCroppedHandler != null) {
419e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
420e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
421e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        cropTask.execute();
422e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
423e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
424e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public interface OnBitmapCroppedHandler {
425e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void onBitmapCropped(byte[] imageBytes);
426e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
427e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
428e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka    protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
429e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Uri mInUri = null;
430e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Context mContext;
431e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String mInFilePath;
432e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        byte[] mInImageBytes;
433e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mInResId = 0;
434e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF mCropBounds = null;
435e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        int mOutWidth, mOutHeight;
43669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        int mRotation;
437e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String mOutputFormat = "jpg"; // for now
438e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mSetWallpaper;
439e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mSaveCroppedBitmap;
440e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap mCroppedBitmap;
441e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable mOnEndRunnable;
442e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Resources mResources;
443e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        OnBitmapCroppedHandler mOnBitmapCroppedHandler;
444e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        boolean mNoCrop;
445e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
446e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(Context c, String filePath,
44769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                RectF cropBounds, int rotation, int outWidth, int outHeight,
448e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
449e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mContext = c;
450e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInFilePath = filePath;
45169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            init(cropBounds, rotation,
45269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
453e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
454e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
455e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BitmapCropTask(byte[] imageBytes,
45669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                RectF cropBounds, int rotation, int outWidth, int outHeight,
457e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
458e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInImageBytes = imageBytes;
45969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            init(cropBounds, rotation,
46069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
461e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
462e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
463e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        public BitmapCropTask(Context c, Uri inUri,
46469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                RectF cropBounds, int rotation, int outWidth, int outHeight,
465e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
466e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            mContext = c;
467e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInUri = inUri;
46869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            init(cropBounds, rotation,
46969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
470e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
471e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
472e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka        public BitmapCropTask(Context c, Resources res, int inResId,
47369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                RectF cropBounds, int rotation, int outWidth, int outHeight,
474e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
475e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            mContext = c;
476e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInResId = inResId;
477e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mResources = res;
47869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            init(cropBounds, rotation,
47969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
480e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
481e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
48269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
483e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
484e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCropBounds = cropBounds;
48569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka            mRotation = rotation;
486e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOutWidth = outWidth;
487e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOutHeight = outHeight;
488e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mSetWallpaper = setWallpaper;
489e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mSaveCroppedBitmap = saveCroppedBitmap;
490e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnEndRunnable = onEndRunnable;
491e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
492e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
493e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
494e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnBitmapCroppedHandler = handler;
495e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
496e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
497e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setNoCrop(boolean value) {
498e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mNoCrop = value;
499e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
500e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
501e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setOnEndRunnable(Runnable onEndRunnable) {
502e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mOnEndRunnable = onEndRunnable;
503e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
504e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
505e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Helper to setup input stream
5067b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka        private InputStream regenerateInputStream() {
507e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
508e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
509e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        "image byte array given");
510e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
511e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
512e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mInUri != null) {
5137b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return new BufferedInputStream(
514e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                                mContext.getContentResolver().openInputStream(mInUri));
515e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else if (mInFilePath != null) {
5167b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return mContext.openFileInput(mInFilePath);
517e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else if (mInImageBytes != null) {
5187b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes));
519e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    } else {
5207b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return new BufferedInputStream(mResources.openRawResource(mInResId));
521e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
522e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (FileNotFoundException e) {
523e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
524e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
525e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
5267b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            return null;
527e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
528e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
529e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Point getImageBounds() {
5307b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            InputStream is = regenerateInputStream();
5317b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            if (is != null) {
532e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                BitmapFactory.Options options = new BitmapFactory.Options();
533e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                options.inJustDecodeBounds = true;
5347b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                BitmapFactory.decodeStream(is, null, options);
5357b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                Utils.closeSilently(is);
536e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (options.outWidth != 0 && options.outHeight != 0) {
537e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return new Point(options.outWidth, options.outHeight);
538e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
539e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
540e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return null;
541e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
542e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
543e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void setCropBounds(RectF cropBounds) {
544e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCropBounds = cropBounds;
545e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
546e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
547e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Bitmap getCroppedBitmap() {
548e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return mCroppedBitmap;
549e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
550e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean cropBitmap() {
551e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            boolean failure = false;
552e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
553e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
554e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            WallpaperManager wallpaperManager = null;
555e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            if (mSetWallpaper) {
556e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
557e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            }
5587b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka
5597b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka
5607b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            if (mSetWallpaper && mNoCrop) {
561e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
5627b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    InputStream is = regenerateInputStream();
5637b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    if (is != null) {
5647b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        wallpaperManager.setStream(is);
5657b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        Utils.closeSilently(is);
5667b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    }
567e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (IOException e) {
568e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot write stream to wallpaper", e);
569e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
570e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
571e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return !failure;
5727b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka            } else {
573e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Find crop bounds (scaled to original image size)
574e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Rect roundedTrueCrop = new Rect();
57569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                Matrix rotateMatrix = new Matrix();
57669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                Matrix inverseRotateMatrix = new Matrix();
577c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka
578c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                Point bounds = getImageBounds();
57969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                if (mRotation > 0) {
58069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    rotateMatrix.setRotate(mRotation);
58169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    inverseRotateMatrix.setRotate(-mRotation);
58269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
58369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    mCropBounds.roundOut(roundedTrueCrop);
58469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    mCropBounds = new RectF(roundedTrueCrop);
58569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
5867b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    if (bounds == null) {
5877b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        Log.w(LOGTAG, "cannot get bounds for image");
5887b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        failure = true;
5897b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return false;
5907b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    }
59169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
59269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    float[] rotatedBounds = new float[] { bounds.x, bounds.y };
59369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    rotateMatrix.mapPoints(rotatedBounds);
59469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    rotatedBounds[0] = Math.abs(rotatedBounds[0]);
59569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    rotatedBounds[1] = Math.abs(rotatedBounds[1]);
59669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
59769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
59869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    inverseRotateMatrix.mapRect(mCropBounds);
59969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    mCropBounds.offset(bounds.x/2, bounds.y/2);
60069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
60169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                }
60269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
603e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mCropBounds.roundOut(roundedTrueCrop);
604e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
605e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
606e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "crop has bad values for full size image");
607e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
608e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return false;
609e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
610e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
611e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // See how much we're reducing the size of the image
612b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
613b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                        roundedTrueCrop.height() / mOutHeight));
614e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Attempt to open a region decoder
615e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                BitmapRegionDecoder decoder = null;
616b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                InputStream is = null;
617e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                try {
618b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                    is = regenerateInputStream();
6197b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    if (is == null) {
6207b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
6217b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        failure = true;
6227b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        return false;
6237b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    }
6247b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    decoder = BitmapRegionDecoder.newInstance(is, false);
6257b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    Utils.closeSilently(is);
626e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } catch (IOException e) {
627e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
628b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                } finally {
629b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                   Utils.closeSilently(is);
630b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                   is = null;
631e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
632e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
633e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                Bitmap crop = null;
634e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (decoder != null) {
635e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // Do region decoding to get crop bitmap
636e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    BitmapFactory.Options options = new BitmapFactory.Options();
637e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (scaleDownSampleSize > 1) {
638e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        options.inSampleSize = scaleDownSampleSize;
639e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
640e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    crop = decoder.decodeRegion(roundedTrueCrop, options);
641e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    decoder.recycle();
642e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
643e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
644e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop == null) {
645e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // BitmapRegionDecoder has failed, try to crop in-memory
646b2552648cec772c896ff31a7aa52ae48380459c0Michael Jurka                    is = regenerateInputStream();
647e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap fullSize = null;
6487b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                    if (is != null) {
649e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        BitmapFactory.Options options = new BitmapFactory.Options();
650e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        if (scaleDownSampleSize > 1) {
651e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            options.inSampleSize = scaleDownSampleSize;
652e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
6537b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        fullSize = BitmapFactory.decodeStream(is, null, options);
6547b215cb92288aa0a21bc773511ddd537b8fbb459Michael Jurka                        Utils.closeSilently(is);
655e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
656e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (fullSize != null) {
657c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        // Find out the true sample size that was used by the decoder
658c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        scaleDownSampleSize = bounds.x / fullSize.getWidth();
65969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mCropBounds.left /= scaleDownSampleSize;
66069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mCropBounds.top /= scaleDownSampleSize;
66169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mCropBounds.bottom /= scaleDownSampleSize;
66269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mCropBounds.right /= scaleDownSampleSize;
66369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mCropBounds.roundOut(roundedTrueCrop);
66469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
665c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        // Adjust values to account for issues related to rounding
666c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        if (roundedTrueCrop.width() > fullSize.getWidth()) {
667c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            // Adjust the width
668c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth();
669c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        }
670c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        if (roundedTrueCrop.right > fullSize.getWidth()) {
671c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            // Adjust the left value
672c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            int adjustment = roundedTrueCrop.left -
673c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                                    Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width());
674c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.left -= adjustment;
675c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.right -= adjustment;
676c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        }
677c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        if (roundedTrueCrop.height() > fullSize.getHeight()) {
678c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            // Adjust the height
679c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight();
680c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        }
681c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        if (roundedTrueCrop.bottom > fullSize.getHeight()) {
682c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            // Adjust the top value
683c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            int adjustment = roundedTrueCrop.top -
684c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                                    Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height());
685c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.top -= adjustment;
686c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                            roundedTrueCrop.bottom -= adjustment;
687c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                        }
688c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka
689e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
690e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                roundedTrueCrop.top, roundedTrueCrop.width(),
691e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                                roundedTrueCrop.height());
692e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
693e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
694e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
695e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop == null) {
696e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
697e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
698e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    return false;
699e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
70069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
70169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
70269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    rotateMatrix.mapPoints(dimsAfter);
70369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    dimsAfter[0] = Math.abs(dimsAfter[0]);
70469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    dimsAfter[1] = Math.abs(dimsAfter[1]);
70569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
70669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    if (!(mOutWidth > 0 && mOutHeight > 0)) {
70769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mOutWidth = Math.round(dimsAfter[0]);
70869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        mOutHeight = Math.round(dimsAfter[1]);
709e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
71069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
71169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
712e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
71369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
71469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    Matrix m = new Matrix();
71569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    if (mRotation == 0) {
71669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
71769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    } else {
71869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix m1 = new Matrix();
71969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
72069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix m2 = new Matrix();
72169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m2.setRotate(mRotation);
72269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix m3 = new Matrix();
72369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
72469784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix m4 = new Matrix();
72569784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
72669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
72769784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix c1 = new Matrix();
72869784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        c1.setConcat(m2, m1);
72969784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        Matrix c2 = new Matrix();
73069784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        c2.setConcat(m4, m3);
73169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                        m.setConcat(c2, c1);
73269784065ea78550944b7eddb559c0dac952e20e8Michael Jurka                    }
73369784065ea78550944b7eddb559c0dac952e20e8Michael Jurka
734e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
735e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            (int) returnRect.height(), Bitmap.Config.ARGB_8888);
736e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (tmp != null) {
737e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Canvas c = new Canvas(tmp);
738e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                        Paint p = new Paint();
739e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                        p.setFilterBitmap(true);
740e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                        c.drawBitmap(crop, m, p);
741e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        crop = tmp;
742e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
743e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
744e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
745e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (mSaveCroppedBitmap) {
746e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    mCroppedBitmap = crop;
747e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
748e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
749e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Get output compression format
750e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                CompressFormat cf =
751e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
752e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
753e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Compress to byte array
754e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
755e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
756e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // If we need to set to the wallpaper, set it
757e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                    if (mSetWallpaper && wallpaperManager != null) {
758e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                        try {
759e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                            byte[] outByteArray = tmpOut.toByteArray();
760e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                            wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
761e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                            if (mOnBitmapCroppedHandler != null) {
762e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                                mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
763e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                            }
764e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                        } catch (IOException e) {
765e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                            Log.w(LOGTAG, "cannot write stream to wallpaper", e);
766e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                            failure = true;
767e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        }
768e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
769e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else {
770e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Log.w(LOGTAG, "cannot compress bitmap");
771e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    failure = true;
772e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
773e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
774e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return !failure; // True if any of the operations failed
775e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
776e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
777e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
778e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        protected Boolean doInBackground(Void... params) {
779e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return cropBitmap();
780e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
781e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
782e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
783e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        protected void onPostExecute(Boolean result) {
784e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            if (mOnEndRunnable != null) {
785e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka                mOnEndRunnable.run();
786e72aa7f0a64ff55f747751b7972ccb8acebab7daMichael Jurka            }
787e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
788e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
789e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
790e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void updateWallpaperDimensions(int width, int height) {
791e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String spKey = getSharedPreferencesKey();
792eed96a0b9088dcce121ffee476b4d7fa72686e77Michael Jurka        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
793e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        SharedPreferences.Editor editor = sp.edit();
794e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (width != 0 && height != 0) {
795e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.putInt(WALLPAPER_WIDTH_KEY, width);
796e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.putInt(WALLPAPER_HEIGHT_KEY, height);
797e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
798e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.remove(WALLPAPER_WIDTH_KEY);
799e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            editor.remove(WALLPAPER_HEIGHT_KEY);
800e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
801e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        editor.commit();
802e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
803e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        suggestWallpaperDimension(getResources(),
804e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                sp, getWindowManager(), WallpaperManager.getInstance(this));
805e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
806e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
807e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    static public void suggestWallpaperDimension(Resources res,
808e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final SharedPreferences sharedPrefs,
809e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            WindowManager windowManager,
810e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final WallpaperManager wallpaperManager) {
81169784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager);
812e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
813c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka        new AsyncTask<Void, Void, Void>() {
814c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka            public Void doInBackground(Void ... args) {
815e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // If we have saved a wallpaper width/height, use that instead
816e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
817e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
818e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
819c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka                return null;
820e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
821c82618c660bbb76df05c11c548cc01724f5e5fc9Michael Jurka        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
822e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
823e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
824e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static RectF getMaxCropRect(
825e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
826e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        RectF cropRect = new RectF();
827e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Get a crop rect that will fit this
828e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
829e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.top = 0;
830e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.bottom = inHeight;
831e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
832e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             cropRect.right = inWidth - cropRect.left;
833e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             if (leftAligned) {
834e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                 cropRect.right -= cropRect.left;
835e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                 cropRect.left = 0;
836e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka             }
837e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
838e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.left = 0;
839e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.right = inWidth;
840e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
841e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            cropRect.bottom = inHeight - cropRect.top;
842e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
843e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return cropRect;
844e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
845e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
846e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static CompressFormat convertExtensionToCompressFormat(String extension) {
847e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
848e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
849e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
850e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static String getFileExtension(String requestFormat) {
851e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        String outputFormat = (requestFormat == null)
852e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? "jpg"
853e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : requestFormat;
854e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        outputFormat = outputFormat.toLowerCase();
855e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return (outputFormat.equals("png") || outputFormat.equals("gif"))
856e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                ? "png" // We don't support gif compression.
857e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                : "jpg";
858e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
859e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka}
860