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