WallpaperCropActivity.java revision b24af13c8359963ecdea420a1b395149e7477f83
1f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka/* 2f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Copyright (C) 2013 The Android Open Source Project 3f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 4f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * you may not use this file except in compliance with the License. 6f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * You may obtain a copy of the License at 7f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 8f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 10f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Unless required by applicable law or agreed to in writing, software 11f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * See the License for the specific language governing permissions and 14f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * limitations under the License. 15f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 16f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 17f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapackage com.android.launcher3; 18f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 19f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.app.ActionBar; 20f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.app.Activity; 21f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.app.WallpaperManager; 22f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.Context; 23f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.Intent; 24f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.SharedPreferences; 25f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.res.Configuration; 26f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.content.res.Resources; 27f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Bitmap; 28f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Bitmap.CompressFormat; 29f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.BitmapFactory; 30f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.BitmapRegionDecoder; 31f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Canvas; 32f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Matrix; 33f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Paint; 34f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Point; 35f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Rect; 36f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.RectF; 37f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.net.Uri; 38f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.os.AsyncTask; 39f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.os.Bundle; 40f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.util.Log; 41f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.view.Display; 42f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.view.View; 43f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.view.WindowManager; 44f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.widget.Toast; 45f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 46f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.common.Utils; 47f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.exif.ExifInterface; 48f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.photos.BitmapRegionTileSource; 49f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.photos.BitmapRegionTileSource.BitmapSource; 50f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 51f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.BufferedInputStream; 52f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.ByteArrayInputStream; 53f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.ByteArrayOutputStream; 54f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.FileNotFoundException; 55f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.IOException; 56f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.io.InputStream; 57f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 58f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapublic class WallpaperCropActivity extends Activity { 59f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static final String LOGTAG = "Launcher3.CropActivity"; 60f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 61f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width"; 62f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height"; 63f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static final int DEFAULT_COMPRESS_QUALITY = 90; 64f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka /** 65f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * The maximum bitmap size we allow to be returned through the intent. 66f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Intents have a maximum of 1MB in total size. However, the Bitmap seems to 67f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * have some overhead to hit so that we go way below the limit here to make 68f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * sure the intent stays below 1MB.We should consider just returning a byte 69f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * array instead of a Bitmap instance to avoid overhead. 70f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 71f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static final int MAX_BMAP_IN_INTENT = 750000; 72f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static final float WALLPAPER_SCREENS_SPAN = 2f; 73f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 74f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static Point sDefaultWallpaperSize; 75f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 76f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected CropView mCropView; 77f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected Uri mUri; 7812d9d42afb5bd750ab52e38cd66f6081f4bd76bfSelim Cinek protected View mSetWallpaperButton; 79f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 80f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 81f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void onCreate(Bundle savedInstanceState) { 82f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka super.onCreate(savedInstanceState); 83f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka init(); 84f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (!enableRotation()) { 85f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT); 86f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 87f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 88f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 89f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void init() { 90f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setContentView(R.layout.wallpaper_cropper); 91f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 92f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropView = (CropView) findViewById(R.id.cropView); 93f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 94f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Intent cropIntent = getIntent(); 95f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final Uri imageUri = cropIntent.getData(); 96f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 97f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (imageUri == null) { 98f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity"); 99f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka finish(); 100f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return; 101f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 102f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 103f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Action bar 104f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Show the custom action bar view 105f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final ActionBar actionBar = getActionBar(); 106f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka actionBar.setCustomView(R.layout.actionbar_set_wallpaper); 107f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka actionBar.getCustomView().setOnClickListener( 108f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka new View.OnClickListener() { 109f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 110f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void onClick(View v) { 111f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean finishActivityWhenDone = true; 112f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone); 113f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 114f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }); 115c192530433ab03c02462635e9ffbe3781b666e13Michael Jurka mSetWallpaperButton = findViewById(R.id.set_wallpaper_button); 116f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 117f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Load image in background 118f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final BitmapRegionTileSource.UriBitmapSource bitmapSource = 119f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024); 12012d9d42afb5bd750ab52e38cd66f6081f4bd76bfSelim Cinek mSetWallpaperButton.setEnabled(false); 121f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Runnable onLoad = new Runnable() { 122f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void run() { 123f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) { 124f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Toast.makeText(WallpaperCropActivity.this, 125f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka getString(R.string.wallpaper_load_fail), 126f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Toast.LENGTH_LONG).show(); 127f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka finish(); 128c192530433ab03c02462635e9ffbe3781b666e13Michael Jurka } else { 12912d9d42afb5bd750ab52e38cd66f6081f4bd76bfSelim Cinek mSetWallpaperButton.setEnabled(true); 130f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 131f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 132f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }; 133f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setCropViewTileSource(bitmapSource, true, false, onLoad); 134f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 135f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 136f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void setCropViewTileSource( 137f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, 138f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final boolean moveToLeft, final Runnable postExecute) { 139f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final Context context = WallpaperCropActivity.this; 140f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final View progressView = findViewById(R.id.loading); 141f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() { 142f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected Void doInBackground(Void...args) { 143f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (!isCancelled()) { 144d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek try { 145d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek bitmapSource.loadInBackground(); 146d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek } catch (SecurityException securityException) { 147d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek if (isDestroyed()) { 148d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // Temporarily granted permissions are revoked when the activity 149d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // finishes, potentially resulting in a SecurityException here. 150d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // Even though {@link #isDestroyed} might also return true in different 151d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // situations where the configuration changes, we are fine with 152d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // catching these cases here as well. 153d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek cancel(false); 154d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek } else { 155d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek // otherwise it had a different cause and we throw it further 156d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek throw securityException; 157d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek } 158d444a550ec1c8992fbac0a036b293fc4759d25c1Selim Cinek } 159f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 160f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 161f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 162f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void onPostExecute(Void arg) { 163f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (!isCancelled()) { 164f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka progressView.setVisibility(View.INVISIBLE); 165f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { 166f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropView.setTileSource( 167f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka new BitmapRegionTileSource(context, bitmapSource), null); 168f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropView.setTouchEnabled(touchEnabled); 169f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (moveToLeft) { 170f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropView.moveToLeft(); 171f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 172f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 173f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 174f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (postExecute != null) { 175f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka postExecute.run(); 176f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 177f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 178f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }; 179f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // We don't want to show the spinner every time we load an image, because that would be 180f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // annoying; instead, only start showing the spinner if loading the image has taken 181f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // longer than 1 sec (ie 1000 ms) 182f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka progressView.postDelayed(new Runnable() { 183f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void run() { 184f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (loadBitmapTask.getStatus() != AsyncTask.Status.FINISHED) { 185f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka progressView.setVisibility(View.VISIBLE); 186f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 187f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 188f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }, 1000); 189f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka loadBitmapTask.execute(); 190f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 191f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 192f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public boolean enableRotation() { 193f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return getResources().getBoolean(R.bool.allow_rotation); 194f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 195f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 196f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static String getSharedPreferencesKey() { 197f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return WallpaperCropActivity.class.getName(); 198f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 199f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 200f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // As a ratio of screen height, the total distance we want the parallax effect to span 201f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // horizontally 202f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static float wallpaperTravelToScreenWidthRatio(int width, int height) { 203f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float aspectRatio = width / (float) height; 204f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 205f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width 206f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width 207f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // We will use these two data points to extrapolate how much the wallpaper parallax effect 208f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // to span (ie travel) at any aspect ratio: 209f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 210f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float ASPECT_RATIO_LANDSCAPE = 16/10f; 211f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float ASPECT_RATIO_PORTRAIT = 10/16f; 212f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; 213f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; 214f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 215f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // To find out the desired width at different aspect ratios, we use the following two 216f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // formulas, where the coefficient on x is the aspect ratio (width/height): 217f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // (16/10)x + y = 1.5 218f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // (10/16)x + y = 1.2 219f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // We solve for x and y and end up with a final formula: 220f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float x = 221f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / 222f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); 223f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; 224f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return x * aspectRatio + y; 225f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 226f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 227f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) { 228f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (sDefaultWallpaperSize == null) { 229f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point minDims = new Point(); 230f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point maxDims = new Point(); 231f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); 232f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 233f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int maxDim = Math.max(maxDims.x, maxDims.y); 234f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int minDim = Math.max(minDims.x, minDims.y); 235f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 236f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { 237f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point realSize = new Point(); 238f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka windowManager.getDefaultDisplay().getRealSize(realSize); 239f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka maxDim = Math.max(realSize.x, realSize.y); 240f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka minDim = Math.min(realSize.x, realSize.y); 241f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 242f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 243f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // We need to ensure that there is enough extra space in the wallpaper 244f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // for the intended parallax effects 245f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final int defaultWidth, defaultHeight; 246f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (isScreenLarge(res)) { 247f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); 248f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka defaultHeight = maxDim; 249f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 250f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); 251f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka defaultHeight = maxDim; 252f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 253f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka sDefaultWallpaperSize = new Point(defaultWidth, defaultHeight); 254f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 255f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return sDefaultWallpaperSize; 256f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 257f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 258f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static int getRotationFromExif(String path) { 259f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return getRotationFromExifHelper(path, null, 0, null, null); 260f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 261f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 262f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static int getRotationFromExif(Context context, Uri uri) { 263f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return getRotationFromExifHelper(null, null, 0, context, uri); 264f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 265f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 266f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public static int getRotationFromExif(Resources res, int resId) { 267f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return getRotationFromExifHelper(null, res, resId, null, null); 268f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 269f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 270f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static int getRotationFromExifHelper( 271f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka String path, Resources res, int resId, Context context, Uri uri) { 272f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ExifInterface ei = new ExifInterface(); 273f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka InputStream is = null; 274f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BufferedInputStream bis = null; 275f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 276f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (path != null) { 277f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ei.readExif(path); 278f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else if (uri != null) { 279f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka is = context.getContentResolver().openInputStream(uri); 280f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka bis = new BufferedInputStream(is); 281f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ei.readExif(bis); 282f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 283f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka is = res.openRawResource(resId); 284f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka bis = new BufferedInputStream(is); 285f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ei.readExif(bis); 286f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 287f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); 288f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (ori != null) { 289f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return ExifInterface.getRotationForOrientationValue(ori.shortValue()); 290f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 291f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (IOException e) { 292f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "Getting exif data failed", e); 2936a56c7c9a4a8d8c3f76202e4f9e23f95068b41b8Michael Jurka } catch (NullPointerException e) { 2946a56c7c9a4a8d8c3f76202e4f9e23f95068b41b8Michael Jurka // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid 2956a56c7c9a4a8d8c3f76202e4f9e23f95068b41b8Michael Jurka Log.w(LOGTAG, "Getting exif data failed", e); 296f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } finally { 297f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(bis); 298f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 299f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 300f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return 0; 301f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 302f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 303f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) { 304f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int rotation = getRotationFromExif(filePath); 305f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapCropTask cropTask = new BitmapCropTask( 306f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka this, filePath, null, rotation, 0, 0, true, false, null); 307f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final Point bounds = cropTask.getImageBounds(); 308f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Runnable onEndCrop = new Runnable() { 309f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void run() { 310f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka updateWallpaperDimensions(bounds.x, bounds.y); 311f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (finishActivityWhenDone) { 312f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setResult(Activity.RESULT_OK); 313f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka finish(); 314f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 315f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 316f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }; 317f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.setOnEndRunnable(onEndCrop); 318f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.setNoCrop(true); 319f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.execute(); 320f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 321f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 322f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void cropImageAndSetWallpaper( 323f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Resources res, int resId, final boolean finishActivityWhenDone) { 324f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // crop this image and scale it down to the default wallpaper size for 325f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // this device 326f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int rotation = getRotationFromExif(res, resId); 327f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point inSize = mCropView.getSourceDimensions(); 328f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point outSize = getDefaultWallpaperSize(getResources(), 329f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka getWindowManager()); 330f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF crop = getMaxCropRect( 331f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka inSize.x, inSize.y, outSize.x, outSize.y, false); 332f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Runnable onEndCrop = new Runnable() { 333f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void run() { 334f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Passing 0, 0 will cause launcher to revert to using the 335f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // default wallpaper size 336f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka updateWallpaperDimensions(0, 0); 337f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (finishActivityWhenDone) { 338f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setResult(Activity.RESULT_OK); 339f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka finish(); 340f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 341f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 342f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }; 343f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapCropTask cropTask = new BitmapCropTask(this, res, resId, 344f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka crop, rotation, outSize.x, outSize.y, true, false, onEndCrop); 345f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.execute(); 346f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 347f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 348f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private static boolean isScreenLarge(Resources res) { 349f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Configuration config = res.getConfiguration(); 350f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return config.smallestScreenWidthDp >= 720; 351f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 352f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 353f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void cropImageAndSetWallpaper(Uri uri, 354f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) { 355942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka boolean centerCrop = getResources().getBoolean(R.bool.center_crop); 356f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Get the crop 357f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; 358f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 359f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Display d = getWindowManager().getDefaultDisplay(); 360f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 361f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point displaySize = new Point(); 362f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka d.getSize(displaySize); 363f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean isPortrait = displaySize.x < displaySize.y; 364f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 365f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(), 366f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka getWindowManager()); 367f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Get the crop 368f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropRect = mCropView.getCrop(); 369b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek 370b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek // due to rounding errors in the cropview renderer the edges can be slightly offset 371b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek // therefore we ensure that the boundaries are sanely defined 372b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek cropRect.left = Math.max(0, cropRect.left); 373b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek cropRect.right = Math.min(mCropView.getWidth(), cropRect.right); 374b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek cropRect.top = Math.max(0, cropRect.top); 375b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek cropRect.bottom = Math.min(mCropView.getHeight(), cropRect.bottom); 376b24af13c8359963ecdea420a1b395149e7477f83Selim Cinek 377f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int cropRotation = mCropView.getImageRotation(); 378f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float cropScale = mCropView.getWidth() / (float) cropRect.width(); 379f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 380f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point inSize = mCropView.getSourceDimensions(); 381f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix rotateMatrix = new Matrix(); 382f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotateMatrix.setRotate(cropRotation); 383f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float[] rotatedInSize = new float[] { inSize.x, inSize.y }; 384f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotateMatrix.mapPoints(rotatedInSize); 385f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotatedInSize[0] = Math.abs(rotatedInSize[0]); 386f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotatedInSize[1] = Math.abs(rotatedInSize[1]); 387f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 388f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // ADJUST CROP WIDTH 389f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Extend the crop all the way to the right, for parallax 390f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // (or all the way to the left, in RTL) 391942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka float extraSpace; 392942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka if (centerCrop) { 393942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka extraSpace = 2f * Math.min(rotatedInSize[0] - cropRect.right, cropRect.left); 394942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka } else { 395942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left; 396942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka } 397f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Cap the amount of extra width 398f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width(); 399f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka extraSpace = Math.min(extraSpace, maxExtraSpace); 400f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 401942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka if (centerCrop) { 402942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka cropRect.left -= extraSpace / 2f; 403942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka cropRect.right += extraSpace / 2f; 404f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 405942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka if (ltr) { 406942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka cropRect.right += extraSpace; 407942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka } else { 408942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka cropRect.left -= extraSpace; 409942b9eefdc1a918ccc259a54bc61cb7fbfb03bfdMichael Jurka } 410f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 411f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 412f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // ADJUST CROP HEIGHT 413f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (isPortrait) { 414f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale; 415f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { // LANDSCAPE 416f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float extraPortraitHeight = 417f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka defaultWallpaperSize.y / cropScale - cropRect.height(); 418f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float expandHeight = 419f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top), 420f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka extraPortraitHeight / 2); 421f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.top -= expandHeight; 422f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.bottom += expandHeight; 423f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 424f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final int outWidth = (int) Math.round(cropRect.width() * cropScale); 425f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final int outHeight = (int) Math.round(cropRect.height() * cropScale); 426f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 427f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Runnable onEndCrop = new Runnable() { 428f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void run() { 429f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka updateWallpaperDimensions(outWidth, outHeight); 430f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (finishActivityWhenDone) { 431f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setResult(Activity.RESULT_OK); 432f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka finish(); 433f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 434f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 435f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka }; 436f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapCropTask cropTask = new BitmapCropTask(this, uri, 437f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop); 438f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (onBitmapCroppedHandler != null) { 439f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.setOnBitmapCropped(onBitmapCroppedHandler); 440f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 441f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropTask.execute(); 442f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 443f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 444f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public interface OnBitmapCroppedHandler { 445f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void onBitmapCropped(byte[] imageBytes); 446f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 447f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 448f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> { 449f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Uri mInUri = null; 450f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Context mContext; 451f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka String mInFilePath; 452f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka byte[] mInImageBytes; 453f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mInResId = 0; 454f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF mCropBounds = null; 455f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mOutWidth, mOutHeight; 456f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int mRotation; 457f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka String mOutputFormat = "jpg"; // for now 458f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean mSetWallpaper; 459f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean mSaveCroppedBitmap; 460f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap mCroppedBitmap; 461f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Runnable mOnEndRunnable; 462f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Resources mResources; 463f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka OnBitmapCroppedHandler mOnBitmapCroppedHandler; 464f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean mNoCrop; 465f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 466f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public BitmapCropTask(Context c, String filePath, 467f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropBounds, int rotation, int outWidth, int outHeight, 468f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 469f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContext = c; 470f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mInFilePath = filePath; 471f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka init(cropBounds, rotation, 472f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 473f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 474f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 475f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public BitmapCropTask(byte[] imageBytes, 476f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropBounds, int rotation, int outWidth, int outHeight, 477f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 478f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mInImageBytes = imageBytes; 479f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka init(cropBounds, rotation, 480f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 481f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 482f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 483f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public BitmapCropTask(Context c, Uri inUri, 484f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropBounds, int rotation, int outWidth, int outHeight, 485f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 486f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContext = c; 487f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mInUri = inUri; 488f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka init(cropBounds, rotation, 489f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 490f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 491f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 492f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public BitmapCropTask(Context c, Resources res, int inResId, 493f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropBounds, int rotation, int outWidth, int outHeight, 494f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 495f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContext = c; 496f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mInResId = inResId; 497f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mResources = res; 498f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka init(cropBounds, rotation, 499f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 500f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 501f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 502f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private void init(RectF cropBounds, int rotation, int outWidth, int outHeight, 503f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 504f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds = cropBounds; 505f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mRotation = rotation; 506f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOutWidth = outWidth; 507f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOutHeight = outHeight; 508f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mSetWallpaper = setWallpaper; 509f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mSaveCroppedBitmap = saveCroppedBitmap; 510f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOnEndRunnable = onEndRunnable; 511f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 512f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 513f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void setOnBitmapCropped(OnBitmapCroppedHandler handler) { 514f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOnBitmapCroppedHandler = handler; 515f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 516f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 517f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void setNoCrop(boolean value) { 518f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mNoCrop = value; 519f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 520f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 521f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void setOnEndRunnable(Runnable onEndRunnable) { 522f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOnEndRunnable = onEndRunnable; 523f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 524f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 525f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Helper to setup input stream 526f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private InputStream regenerateInputStream() { 527f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { 528f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + 529f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka "image byte array given"); 530f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 531f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 532f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mInUri != null) { 533f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new BufferedInputStream( 534f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContext.getContentResolver().openInputStream(mInUri)); 535f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else if (mInFilePath != null) { 536f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mContext.openFileInput(mInFilePath); 537f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else if (mInImageBytes != null) { 538f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes)); 539f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 540f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new BufferedInputStream(mResources.openRawResource(mInResId)); 541f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 542f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (FileNotFoundException e) { 543f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); 544f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 545f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 546f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 547f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 548f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 549f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Point getImageBounds() { 550f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka InputStream is = regenerateInputStream(); 551f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (is != null) { 552f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapFactory.Options options = new BitmapFactory.Options(); 553f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka options.inJustDecodeBounds = true; 554f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapFactory.decodeStream(is, null, options); 555f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 556f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (options.outWidth != 0 && options.outHeight != 0) { 557f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return new Point(options.outWidth, options.outHeight); 558f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 559f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 560f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return null; 561f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 562f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 563f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void setCropBounds(RectF cropBounds) { 564f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds = cropBounds; 565f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 566f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 567f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public Bitmap getCroppedBitmap() { 568f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mCroppedBitmap; 569f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 570f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public boolean cropBitmap() { 571f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka boolean failure = false; 572f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 573f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 574f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka WallpaperManager wallpaperManager = null; 575f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mSetWallpaper) { 576f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext()); 577f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 578f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 579f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 580f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mSetWallpaper && mNoCrop) { 581f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 582f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka InputStream is = regenerateInputStream(); 583f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (is != null) { 584f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wallpaperManager.setStream(is); 585f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 586f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 587f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (IOException e) { 588f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot write stream to wallpaper", e); 589f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 590f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 591f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return !failure; 592f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 593f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Find crop bounds (scaled to original image size) 594f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Rect roundedTrueCrop = new Rect(); 595f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix rotateMatrix = new Matrix(); 596f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix inverseRotateMatrix = new Matrix(); 597f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 598f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Point bounds = getImageBounds(); 599f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mRotation > 0) { 600f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotateMatrix.setRotate(mRotation); 601f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka inverseRotateMatrix.setRotate(-mRotation); 602f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 603f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.roundOut(roundedTrueCrop); 604f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds = new RectF(roundedTrueCrop); 605f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 606f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bounds == null) { 607f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot get bounds for image"); 608f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 609f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return false; 610f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 611f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 612f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float[] rotatedBounds = new float[] { bounds.x, bounds.y }; 613f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotateMatrix.mapPoints(rotatedBounds); 614f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotatedBounds[0] = Math.abs(rotatedBounds[0]); 615f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotatedBounds[1] = Math.abs(rotatedBounds[1]); 616f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 617f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2); 618f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka inverseRotateMatrix.mapRect(mCropBounds); 619f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.offset(bounds.x/2, bounds.y/2); 620f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 621f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 622f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 623f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.roundOut(roundedTrueCrop); 624f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 625f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) { 626f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "crop has bad values for full size image"); 627f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 628f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return false; 629f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 630f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 631f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // See how much we're reducing the size of the image 632f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth, 633f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.height() / mOutHeight)); 634f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Attempt to open a region decoder 635f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapRegionDecoder decoder = null; 636f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka InputStream is = null; 637f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 638f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka is = regenerateInputStream(); 639f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (is == null) { 640f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString()); 641f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 642f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return false; 643f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 644f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka decoder = BitmapRegionDecoder.newInstance(is, false); 645f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 646f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (IOException e) { 647f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); 648f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } finally { 649f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 650f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka is = null; 651f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 652f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 653f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap crop = null; 654f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (decoder != null) { 655f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Do region decoding to get crop bitmap 656f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapFactory.Options options = new BitmapFactory.Options(); 657f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (scaleDownSampleSize > 1) { 658f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka options.inSampleSize = scaleDownSampleSize; 659f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 660f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka crop = decoder.decodeRegion(roundedTrueCrop, options); 661f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka decoder.recycle(); 662f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 663f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 664f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (crop == null) { 665f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // BitmapRegionDecoder has failed, try to crop in-memory 666f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka is = regenerateInputStream(); 667f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap fullSize = null; 668f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (is != null) { 669f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka BitmapFactory.Options options = new BitmapFactory.Options(); 670f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (scaleDownSampleSize > 1) { 671f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka options.inSampleSize = scaleDownSampleSize; 672f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 673f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka fullSize = BitmapFactory.decodeStream(is, null, options); 674f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Utils.closeSilently(is); 675f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 676f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (fullSize != null) { 677f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Find out the true sample size that was used by the decoder 678f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka scaleDownSampleSize = bounds.x / fullSize.getWidth(); 679f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.left /= scaleDownSampleSize; 680f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.top /= scaleDownSampleSize; 681f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.bottom /= scaleDownSampleSize; 682f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.right /= scaleDownSampleSize; 683f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCropBounds.roundOut(roundedTrueCrop); 684f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 685f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Adjust values to account for issues related to rounding 686f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (roundedTrueCrop.width() > fullSize.getWidth()) { 687f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Adjust the width 688f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth(); 689f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 690f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (roundedTrueCrop.right > fullSize.getWidth()) { 691f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Adjust the left value 692f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int adjustment = roundedTrueCrop.left - 693f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width()); 694f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.left -= adjustment; 695f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.right -= adjustment; 696f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 697f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (roundedTrueCrop.height() > fullSize.getHeight()) { 698f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Adjust the height 699f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight(); 700f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 701f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (roundedTrueCrop.bottom > fullSize.getHeight()) { 702f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Adjust the top value 703f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int adjustment = roundedTrueCrop.top - 704f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height()); 705f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.top -= adjustment; 706f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.bottom -= adjustment; 707f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 708f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 709f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, 710f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.top, roundedTrueCrop.width(), 711f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka roundedTrueCrop.height()); 712f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 713f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 714f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 715f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (crop == null) { 716f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot decode file: " + mInUri.toString()); 717f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 718f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return false; 719f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 720f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) { 721f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() }; 722f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka rotateMatrix.mapPoints(dimsAfter); 723f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka dimsAfter[0] = Math.abs(dimsAfter[0]); 724f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka dimsAfter[1] = Math.abs(dimsAfter[1]); 725f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 726f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (!(mOutWidth > 0 && mOutHeight > 0)) { 727f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOutWidth = Math.round(dimsAfter[0]); 728f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOutHeight = Math.round(dimsAfter[1]); 729f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 730f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 731f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]); 732f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight); 733f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 734f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix m = new Matrix(); 735f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mRotation == 0) { 736f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); 737f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 738f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix m1 = new Matrix(); 739f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f); 740f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix m2 = new Matrix(); 741f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m2.setRotate(mRotation); 742f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix m3 = new Matrix(); 743f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f); 744f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix m4 = new Matrix(); 745f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); 746f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 747f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix c1 = new Matrix(); 748f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka c1.setConcat(m2, m1); 749f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Matrix c2 = new Matrix(); 750f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka c2.setConcat(m4, m3); 751f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka m.setConcat(c2, c1); 752f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 753f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 754f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), 755f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka (int) returnRect.height(), Bitmap.Config.ARGB_8888); 756f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (tmp != null) { 757f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Canvas c = new Canvas(tmp); 758f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Paint p = new Paint(); 759f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka p.setFilterBitmap(true); 760f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka c.drawBitmap(crop, m, p); 761f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka crop = tmp; 762f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 763f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 764f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 765f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mSaveCroppedBitmap) { 766f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mCroppedBitmap = crop; 767f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 768f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 769f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Get output compression format 770f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka CompressFormat cf = 771f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka convertExtensionToCompressFormat(getFileExtension(mOutputFormat)); 772f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 773f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Compress to byte array 774f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); 775f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) { 776f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // If we need to set to the wallpaper, set it 777f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mSetWallpaper && wallpaperManager != null) { 778f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 779f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka byte[] outByteArray = tmpOut.toByteArray(); 780f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wallpaperManager.setStream(new ByteArrayInputStream(outByteArray)); 781f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mOnBitmapCroppedHandler != null) { 782f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOnBitmapCroppedHandler.onBitmapCropped(outByteArray); 783f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 784f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } catch (IOException e) { 785f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot write stream to wallpaper", e); 786f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 787f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 788f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 789f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 790f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Log.w(LOGTAG, "cannot compress bitmap"); 791f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka failure = true; 792f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 793f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 794f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return !failure; // True if any of the operations failed 795f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 796f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 797f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 798f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected Boolean doInBackground(Void... params) { 799f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return cropBitmap(); 800f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 801f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 802f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 803f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void onPostExecute(Boolean result) { 804f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mOnEndRunnable != null) { 805f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mOnEndRunnable.run(); 806f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 807f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 808f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 809f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 810f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void updateWallpaperDimensions(int width, int height) { 811f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka String spKey = getSharedPreferencesKey(); 812f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); 813f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka SharedPreferences.Editor editor = sp.edit(); 814f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (width != 0 && height != 0) { 815f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka editor.putInt(WALLPAPER_WIDTH_KEY, width); 816f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka editor.putInt(WALLPAPER_HEIGHT_KEY, height); 817f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 818f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka editor.remove(WALLPAPER_WIDTH_KEY); 819f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka editor.remove(WALLPAPER_HEIGHT_KEY); 820f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 821f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka editor.commit(); 822f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 823f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka suggestWallpaperDimension(getResources(), 824f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka sp, getWindowManager(), WallpaperManager.getInstance(this)); 825f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 826f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 827f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka static public void suggestWallpaperDimension(Resources res, 828f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final SharedPreferences sharedPrefs, 829f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka WindowManager windowManager, 830f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final WallpaperManager wallpaperManager) { 831f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager); 832f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // If we have saved a wallpaper width/height, use that instead 833f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x); 834f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y); 835f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (savedWidth != wallpaperManager.getDesiredMinimumWidth() || 836f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka savedHeight != wallpaperManager.getDesiredMinimumHeight()) { 837f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight); 838f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 839f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 840f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 841f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static RectF getMaxCropRect( 842f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) { 843f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka RectF cropRect = new RectF(); 844f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Get a crop rect that will fit this 845f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (inWidth / (float) inHeight > outWidth / (float) outHeight) { 846f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.top = 0; 847f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.bottom = inHeight; 848f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2; 849f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.right = inWidth - cropRect.left; 850f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (leftAligned) { 851f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.right -= cropRect.left; 852f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.left = 0; 853f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 854f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 855f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.left = 0; 856f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.right = inWidth; 857f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2; 858f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka cropRect.bottom = inHeight - cropRect.top; 859f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 860f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return cropRect; 861f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 862f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 863f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static CompressFormat convertExtensionToCompressFormat(String extension) { 864f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG; 865f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 866f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 867f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected static String getFileExtension(String requestFormat) { 868f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka String outputFormat = (requestFormat == null) 869f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ? "jpg" 870f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka : requestFormat; 871f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka outputFormat = outputFormat.toLowerCase(); 872f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return (outputFormat.equals("png") || outputFormat.equals("gif")) 873f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ? "png" // We don't support gif compression. 874f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka : "jpg"; 875f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 876f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 877