blob: 142a9cb10eb21788e9ca11a6e2bbf25e6ab52ae9 [file] [log] [blame]
Michael Jurka104c4562013-07-08 18:03:46 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher3;
18
Sunny Goyal06a4d3f2015-02-12 11:19:39 -080019import android.annotation.TargetApi;
Michael Jurka2d8de582013-09-04 14:42:52 +020020import android.app.ActionBar;
Michael Jurka104c4562013-07-08 18:03:46 -070021import android.app.Activity;
22import android.app.WallpaperManager;
23import android.content.Context;
Michael Jurka2d8de582013-09-04 14:42:52 +020024import android.content.Intent;
Michael Jurka104c4562013-07-08 18:03:46 -070025import android.content.SharedPreferences;
Michael Jurkaadc574c2013-09-12 00:05:02 +020026import android.content.res.Configuration;
Michael Jurkaeadbfc52013-09-04 00:45:37 +020027import android.content.res.Resources;
Sunny Goyal65b929d2015-02-12 15:34:41 -080028import android.graphics.Bitmap;
Michael Jurka104c4562013-07-08 18:03:46 -070029import android.graphics.Matrix;
Michael Jurka104c4562013-07-08 18:03:46 -070030import android.graphics.Point;
Michael Jurka104c4562013-07-08 18:03:46 -070031import android.graphics.RectF;
32import android.net.Uri;
Sunny Goyal06a4d3f2015-02-12 11:19:39 -080033import android.os.Build;
Michael Jurka2d8de582013-09-04 14:42:52 +020034import android.os.Bundle;
Sunny Goyal65b929d2015-02-12 15:34:41 -080035import android.os.Handler;
36import android.os.HandlerThread;
37import android.os.Message;
Michael Jurka104c4562013-07-08 18:03:46 -070038import android.util.Log;
Michael Jurka2d8de582013-09-04 14:42:52 +020039import android.view.Display;
40import android.view.View;
Michael Jurka619a1802013-10-29 15:50:06 +010041import android.widget.Toast;
Sunny Goyal65b929d2015-02-12 15:34:41 -080042
Sunny Goyal06a4d3f2015-02-12 11:19:39 -080043import com.android.gallery3d.common.BitmapCropTask;
44import com.android.gallery3d.common.BitmapUtils;
Michael Jurka104c4562013-07-08 18:03:46 -070045import com.android.gallery3d.common.Utils;
Sunny Goyal1d0b0932015-03-20 18:51:38 -070046import com.android.launcher3.base.BaseActivity;
Adam Cohen091440a2015-03-18 14:16:05 -070047import com.android.launcher3.util.Thunk;
Sunny Goyal6a1e95a2015-03-20 17:26:30 -070048import com.android.launcher3.util.WallpaperUtils;
Michael Jurka2d8de582013-09-04 14:42:52 +020049import com.android.photos.BitmapRegionTileSource;
Michael Jurka619a1802013-10-29 15:50:06 +010050import com.android.photos.BitmapRegionTileSource.BitmapSource;
Sunny Goyal65b929d2015-02-12 15:34:41 -080051import com.android.photos.BitmapRegionTileSource.BitmapSource.InBitmapProvider;
52import com.android.photos.views.TiledImageRenderer.TileSource;
Michael Jurka104c4562013-07-08 18:03:46 -070053
Sunny Goyal65b929d2015-02-12 15:34:41 -080054import java.util.Collections;
Sunny Goyal65b929d2015-02-12 15:34:41 -080055import java.util.Set;
56import java.util.WeakHashMap;
57
Sunny Goyal1d0b0932015-03-20 18:51:38 -070058public class WallpaperCropActivity extends BaseActivity implements Handler.Callback {
Michael Jurka104c4562013-07-08 18:03:46 -070059 private static final String LOGTAG = "Launcher3.CropActivity";
60
Sunny Goyal6a1e95a2015-03-20 17:26:30 -070061 protected static final String WALLPAPER_WIDTH_KEY = WallpaperUtils.WALLPAPER_WIDTH_KEY;
62 protected static final String WALLPAPER_HEIGHT_KEY = WallpaperUtils.WALLPAPER_HEIGHT_KEY;
Sunny Goyal06a4d3f2015-02-12 11:19:39 -080063
Michael Jurka104c4562013-07-08 18:03:46 -070064 /**
65 * The maximum bitmap size we allow to be returned through the intent.
66 * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
67 * have some overhead to hit so that we go way below the limit here to make
68 * sure the intent stays below 1MB.We should consider just returning a byte
69 * array instead of a Bitmap instance to avoid overhead.
70 */
71 public static final int MAX_BMAP_IN_INTENT = 750000;
Sunny Goyal6a1e95a2015-03-20 17:26:30 -070072 public static final float WALLPAPER_SCREENS_SPAN = WallpaperUtils.WALLPAPER_SCREENS_SPAN;
Michael Jurkaa6a05472013-11-13 17:59:46 +010073
Sunny Goyal65b929d2015-02-12 15:34:41 -080074 private static final int MSG_LOAD_IMAGE = 1;
75
Michael Jurka2d8de582013-09-04 14:42:52 +020076 protected CropView mCropView;
Sunny Goyal65b929d2015-02-12 15:34:41 -080077 protected View mProgressView;
Michael Jurka2d8de582013-09-04 14:42:52 +020078 protected Uri mUri;
Selim Cinekffed6582014-02-28 17:18:59 +010079 protected View mSetWallpaperButton;
Michael Jurka2d8de582013-09-04 14:42:52 +020080
Sunny Goyal65b929d2015-02-12 15:34:41 -080081 private HandlerThread mLoaderThread;
82 private Handler mLoaderHandler;
Adam Cohen091440a2015-03-18 14:16:05 -070083 @Thunk LoadRequest mCurrentLoadRequest;
Sunny Goyal65b929d2015-02-12 15:34:41 -080084 private byte[] mTempStorageForDecoding = new byte[16 * 1024];
85 // A weak-set of reusable bitmaps
Adam Cohen091440a2015-03-18 14:16:05 -070086 @Thunk Set<Bitmap> mReusableBitmaps =
Sunny Goyal65b929d2015-02-12 15:34:41 -080087 Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
88
Michael Jurka2d8de582013-09-04 14:42:52 +020089 @Override
Sunny Goyal1d0b0932015-03-20 18:51:38 -070090 public void onCreate(Bundle savedInstanceState) {
Michael Jurka2d8de582013-09-04 14:42:52 +020091 super.onCreate(savedInstanceState);
Sunny Goyal65b929d2015-02-12 15:34:41 -080092
93 mLoaderThread = new HandlerThread("wallpaper_loader");
94 mLoaderThread.start();
95 mLoaderHandler = new Handler(mLoaderThread.getLooper(), this);
96
Michael Jurka2d8de582013-09-04 14:42:52 +020097 init();
Michael Jurka7267fa52013-09-26 15:29:57 -070098 if (!enableRotation()) {
99 setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
100 }
Michael Jurka2d8de582013-09-04 14:42:52 +0200101 }
102
103 protected void init() {
104 setContentView(R.layout.wallpaper_cropper);
105
106 mCropView = (CropView) findViewById(R.id.cropView);
Sunny Goyal65b929d2015-02-12 15:34:41 -0800107 mProgressView = findViewById(R.id.loading);
Michael Jurka2d8de582013-09-04 14:42:52 +0200108
Michael Jurkaf6502c32013-10-14 14:09:21 -0700109 Intent cropIntent = getIntent();
Michael Jurka2d8de582013-09-04 14:42:52 +0200110 final Uri imageUri = cropIntent.getData();
111
Michael Jurkaf6502c32013-10-14 14:09:21 -0700112 if (imageUri == null) {
113 Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity");
114 finish();
115 return;
116 }
117
Michael Jurka2d8de582013-09-04 14:42:52 +0200118 // Action bar
119 // Show the custom action bar view
120 final ActionBar actionBar = getActionBar();
121 actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
122 actionBar.getCustomView().setOnClickListener(
123 new View.OnClickListener() {
124 @Override
125 public void onClick(View v) {
126 boolean finishActivityWhenDone = true;
Michael Jurkabe2f8dd2013-09-10 13:39:59 +0200127 cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
Michael Jurka2d8de582013-09-04 14:42:52 +0200128 }
129 });
Michael Jurka849aff72014-01-16 14:58:00 +0100130 mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
Michael Jurka862f7e32013-10-16 18:23:56 -0700131
132 // Load image in background
Michael Jurka619a1802013-10-29 15:50:06 +0100133 final BitmapRegionTileSource.UriBitmapSource bitmapSource =
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700134 new BitmapRegionTileSource.UriBitmapSource(getContext(), imageUri, 1024);
Selim Cinekffed6582014-02-28 17:18:59 +0100135 mSetWallpaperButton.setEnabled(false);
Michael Jurka619a1802013-10-29 15:50:06 +0100136 Runnable onLoad = new Runnable() {
137 public void run() {
138 if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) {
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700139 Toast.makeText(getContext(), R.string.wallpaper_load_fail,
Michael Jurka619a1802013-10-29 15:50:06 +0100140 Toast.LENGTH_LONG).show();
141 finish();
Michael Jurka849aff72014-01-16 14:58:00 +0100142 } else {
Selim Cinekffed6582014-02-28 17:18:59 +0100143 mSetWallpaperButton.setEnabled(true);
Michael Jurka619a1802013-10-29 15:50:06 +0100144 }
145 }
146 };
Sunny Goyal65b929d2015-02-12 15:34:41 -0800147 setCropViewTileSource(bitmapSource, true, false, null, onLoad);
Michael Jurka862f7e32013-10-16 18:23:56 -0700148 }
149
Sunny Goyale9bacd92014-07-22 09:39:01 -0700150 @Override
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700151 public void onDestroy() {
Sunny Goyale9bacd92014-07-22 09:39:01 -0700152 if (mCropView != null) {
153 mCropView.destroy();
154 }
Sunny Goyal65b929d2015-02-12 15:34:41 -0800155 if (mLoaderThread != null) {
156 mLoaderThread.quit();
157 }
Sunny Goyale9bacd92014-07-22 09:39:01 -0700158 super.onDestroy();
159 }
160
Sunny Goyal65b929d2015-02-12 15:34:41 -0800161 /**
162 * This is called on {@link #mLoaderThread}
163 */
164 @Override
165 public boolean handleMessage(Message msg) {
166 if (msg.what == MSG_LOAD_IMAGE) {
167 final LoadRequest req = (LoadRequest) msg.obj;
168 try {
169 req.src.loadInBackground(new InBitmapProvider() {
170
171 @Override
172 public Bitmap forPixelCount(int count) {
Sunny Goyal9f9d0a52015-02-25 11:34:17 -0800173 Bitmap bitmapToReuse = null;
174 // Find the smallest bitmap that satisfies the pixel count limit
Sunny Goyal65b929d2015-02-12 15:34:41 -0800175 synchronized (mReusableBitmaps) {
Sunny Goyal9f9d0a52015-02-25 11:34:17 -0800176 int currentBitmapSize = Integer.MAX_VALUE;
177 for (Bitmap b : mReusableBitmaps) {
178 int bitmapSize = b.getWidth() * b.getHeight();
179 if ((bitmapSize >= count) && (bitmapSize < currentBitmapSize)) {
180 bitmapToReuse = b;
181 currentBitmapSize = bitmapSize;
Sunny Goyal65b929d2015-02-12 15:34:41 -0800182 }
183 }
Sunny Goyal9f9d0a52015-02-25 11:34:17 -0800184
185 if (bitmapToReuse != null) {
186 mReusableBitmaps.remove(bitmapToReuse);
187 }
Selim Cinek459875d2014-03-04 21:29:40 +0100188 }
Sunny Goyal9f9d0a52015-02-25 11:34:17 -0800189 return bitmapToReuse;
Selim Cinek459875d2014-03-04 21:29:40 +0100190 }
Sunny Goyal65b929d2015-02-12 15:34:41 -0800191 });
192 } catch (SecurityException securityException) {
193 if (isDestroyed()) {
194 // Temporarily granted permissions are revoked when the activity
195 // finishes, potentially resulting in a SecurityException here.
196 // Even though {@link #isDestroyed} might also return true in different
197 // situations where the configuration changes, we are fine with
198 // catching these cases here as well.
199 return true;
200 } else {
201 // otherwise it had a different cause and we throw it further
202 throw securityException;
Michael Jurka619a1802013-10-29 15:50:06 +0100203 }
Michael Jurka862f7e32013-10-16 18:23:56 -0700204 }
Sunny Goyal65b929d2015-02-12 15:34:41 -0800205
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700206 req.result = new BitmapRegionTileSource(getContext(), req.src, mTempStorageForDecoding);
Sunny Goyal65b929d2015-02-12 15:34:41 -0800207 runOnUiThread(new Runnable() {
208
209 @Override
210 public void run() {
211 if (req == mCurrentLoadRequest) {
212 onLoadRequestComplete(req,
213 req.src.getLoadingState() == BitmapSource.State.LOADED);
214 } else {
215 addReusableBitmap(req.result);
216 }
217 }
218 });
219 return true;
220 }
221 return false;
222 }
223
Adam Cohen091440a2015-03-18 14:16:05 -0700224 @Thunk void addReusableBitmap(TileSource src) {
Sunny Goyal65b929d2015-02-12 15:34:41 -0800225 synchronized (mReusableBitmaps) {
226 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
227 && src instanceof BitmapRegionTileSource) {
228 Bitmap preview = ((BitmapRegionTileSource) src).getBitmap();
229 if (preview != null && preview.isMutable()) {
230 mReusableBitmaps.add(preview);
231 }
232 }
233 }
234 }
235
236 protected void onLoadRequestComplete(LoadRequest req, boolean success) {
237 mCurrentLoadRequest = null;
238 if (success) {
239 TileSource oldSrc = mCropView.getTileSource();
240 mCropView.setTileSource(req.result, null);
241 mCropView.setTouchEnabled(req.touchEnabled);
242 if (req.moveToLeft) {
243 mCropView.moveToLeft();
244 }
245 if (req.scaleProvider != null) {
246 mCropView.setScale(req.scaleProvider.getScale(req.result));
247 }
248
249 // Free last image
250 if (oldSrc != null) {
251 // Call yield instead of recycle, as we only want to free GL resource.
252 // We can still reuse the bitmap for decoding any other image.
253 oldSrc.getPreview().yield();
254 }
255 addReusableBitmap(oldSrc);
256 }
257 if (req.postExecute != null) {
258 req.postExecute.run();
259 }
260 }
261
262 public final void setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled,
263 boolean moveToLeft, CropViewScaleProvider scaleProvider, Runnable postExecute) {
264 final LoadRequest req = new LoadRequest();
265 req.moveToLeft = moveToLeft;
266 req.src = bitmapSource;
267 req.touchEnabled = touchEnabled;
268 req.postExecute = postExecute;
269 req.scaleProvider = scaleProvider;
270 mCurrentLoadRequest = req;
271
272 // Remove any pending requests
273 mLoaderHandler.removeMessages(MSG_LOAD_IMAGE);
274 Message.obtain(mLoaderHandler, MSG_LOAD_IMAGE, req).sendToTarget();
275
Michael Jurka862f7e32013-10-16 18:23:56 -0700276 // We don't want to show the spinner every time we load an image, because that would be
277 // annoying; instead, only start showing the spinner if loading the image has taken
278 // longer than 1 sec (ie 1000 ms)
Sunny Goyal65b929d2015-02-12 15:34:41 -0800279 mProgressView.postDelayed(new Runnable() {
Michael Jurka862f7e32013-10-16 18:23:56 -0700280 public void run() {
Sunny Goyal65b929d2015-02-12 15:34:41 -0800281 if (mCurrentLoadRequest == req) {
282 mProgressView.setVisibility(View.VISIBLE);
Michael Jurka862f7e32013-10-16 18:23:56 -0700283 }
284 }
285 }, 1000);
Michael Jurka7267fa52013-09-26 15:29:57 -0700286 }
287
Sunny Goyal65b929d2015-02-12 15:34:41 -0800288
Michael Jurka7267fa52013-09-26 15:29:57 -0700289 public boolean enableRotation() {
290 return getResources().getBoolean(R.bool.allow_rotation);
Michael Jurka2d8de582013-09-04 14:42:52 +0200291 }
292
Sunny Goyalcdc4dbd2014-07-16 16:04:08 -0700293 protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) {
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700294 int rotation = BitmapUtils.getRotationFromExif(getContext(), uri);
Michael Jurka8713a942013-10-10 21:28:40 -0700295 BitmapCropTask cropTask = new BitmapCropTask(
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700296 getContext(), uri, null, rotation, 0, 0, true, false, null);
Michael Jurkabe2f8dd2013-09-10 13:39:59 +0200297 final Point bounds = cropTask.getImageBounds();
298 Runnable onEndCrop = new Runnable() {
299 public void run() {
300 updateWallpaperDimensions(bounds.x, bounds.y);
301 if (finishActivityWhenDone) {
302 setResult(Activity.RESULT_OK);
303 finish();
304 }
305 }
306 };
307 cropTask.setOnEndRunnable(onEndCrop);
308 cropTask.setNoCrop(true);
309 cropTask.execute();
310 }
311
312 protected void cropImageAndSetWallpaper(
313 Resources res, int resId, final boolean finishActivityWhenDone) {
Michael Jurka2d8de582013-09-04 14:42:52 +0200314 // crop this image and scale it down to the default wallpaper size for
315 // this device
Sunny Goyal06a4d3f2015-02-12 11:19:39 -0800316 int rotation = BitmapUtils.getRotationFromExif(res, resId);
Michael Jurka2d8de582013-09-04 14:42:52 +0200317 Point inSize = mCropView.getSourceDimensions();
Sunny Goyal6a1e95a2015-03-20 17:26:30 -0700318 Point outSize = WallpaperUtils.getDefaultWallpaperSize(getResources(),
Michael Jurka2d8de582013-09-04 14:42:52 +0200319 getWindowManager());
Sunny Goyal06a4d3f2015-02-12 11:19:39 -0800320 RectF crop = Utils.getMaxCropRect(
Michael Jurkabe2f8dd2013-09-10 13:39:59 +0200321 inSize.x, inSize.y, outSize.x, outSize.y, false);
Michael Jurka2d8de582013-09-04 14:42:52 +0200322 Runnable onEndCrop = new Runnable() {
323 public void run() {
324 // Passing 0, 0 will cause launcher to revert to using the
325 // default wallpaper size
326 updateWallpaperDimensions(0, 0);
327 if (finishActivityWhenDone) {
328 setResult(Activity.RESULT_OK);
329 finish();
330 }
331 }
332 };
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700333 BitmapCropTask cropTask = new BitmapCropTask(getContext(), res, resId,
Michael Jurka8713a942013-10-10 21:28:40 -0700334 crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
Michael Jurka2d8de582013-09-04 14:42:52 +0200335 cropTask.execute();
336 }
337
Sunny Goyal06a4d3f2015-02-12 11:19:39 -0800338 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
Michael Jurkabe2f8dd2013-09-10 13:39:59 +0200339 protected void cropImageAndSetWallpaper(Uri uri,
Sunny Goyal06a4d3f2015-02-12 11:19:39 -0800340 BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
Michael Jurka4808aa62014-01-14 13:50:53 +0100341 boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
Michael Jurkafe0ace32013-10-03 01:05:14 -0700342 // Get the crop
Michael Jurkafe0ace32013-10-03 01:05:14 -0700343 boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
344
Michael Jurka2d8de582013-09-04 14:42:52 +0200345 Display d = getWindowManager().getDefaultDisplay();
Michael Jurka2d8de582013-09-04 14:42:52 +0200346
347 Point displaySize = new Point();
348 d.getSize(displaySize);
Michael Jurka2d8de582013-09-04 14:42:52 +0200349 boolean isPortrait = displaySize.x < displaySize.y;
Michael Jurka454db972013-10-31 16:32:43 +0100350
Sunny Goyal6a1e95a2015-03-20 17:26:30 -0700351 Point defaultWallpaperSize = WallpaperUtils.getDefaultWallpaperSize(getResources(),
Michael Jurka454db972013-10-31 16:32:43 +0100352 getWindowManager());
Michael Jurka2d8de582013-09-04 14:42:52 +0200353 // Get the crop
354 RectF cropRect = mCropView.getCrop();
Selim Cineke04e8b22014-03-14 18:19:35 +0100355
Selim Cinek7c989e92014-03-24 14:13:20 +0100356 Point inSize = mCropView.getSourceDimensions();
357
Michael Jurka8713a942013-10-10 21:28:40 -0700358 int cropRotation = mCropView.getImageRotation();
Michael Jurka2d8de582013-09-04 14:42:52 +0200359 float cropScale = mCropView.getWidth() / (float) cropRect.width();
360
Selim Cinek7c989e92014-03-24 14:13:20 +0100361
Michael Jurka8713a942013-10-10 21:28:40 -0700362 Matrix rotateMatrix = new Matrix();
363 rotateMatrix.setRotate(cropRotation);
364 float[] rotatedInSize = new float[] { inSize.x, inSize.y };
365 rotateMatrix.mapPoints(rotatedInSize);
366 rotatedInSize[0] = Math.abs(rotatedInSize[0]);
367 rotatedInSize[1] = Math.abs(rotatedInSize[1]);
368
Selim Cinek31442562014-03-27 20:35:19 +0100369
370 // due to rounding errors in the cropview renderer the edges can be slightly offset
371 // therefore we ensure that the boundaries are sanely defined
372 cropRect.left = Math.max(0, cropRect.left);
373 cropRect.right = Math.min(rotatedInSize[0], cropRect.right);
374 cropRect.top = Math.max(0, cropRect.top);
375 cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom);
376
Michael Jurka2d8de582013-09-04 14:42:52 +0200377 // ADJUST CROP WIDTH
378 // Extend the crop all the way to the right, for parallax
Michael Jurkafe0ace32013-10-03 01:05:14 -0700379 // (or all the way to the left, in RTL)
Michael Jurka4808aa62014-01-14 13:50:53 +0100380 float extraSpace;
381 if (centerCrop) {
382 extraSpace = 2f * Math.min(rotatedInSize[0] - cropRect.right, cropRect.left);
383 } else {
384 extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
385 }
Michael Jurka2d8de582013-09-04 14:42:52 +0200386 // Cap the amount of extra width
Michael Jurka454db972013-10-31 16:32:43 +0100387 float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width();
Michael Jurkafe0ace32013-10-03 01:05:14 -0700388 extraSpace = Math.min(extraSpace, maxExtraSpace);
Michael Jurka2d8de582013-09-04 14:42:52 +0200389
Michael Jurka4808aa62014-01-14 13:50:53 +0100390 if (centerCrop) {
391 cropRect.left -= extraSpace / 2f;
392 cropRect.right += extraSpace / 2f;
Michael Jurkafe0ace32013-10-03 01:05:14 -0700393 } else {
Michael Jurka4808aa62014-01-14 13:50:53 +0100394 if (ltr) {
395 cropRect.right += extraSpace;
396 } else {
397 cropRect.left -= extraSpace;
398 }
Michael Jurkafe0ace32013-10-03 01:05:14 -0700399 }
Michael Jurka2d8de582013-09-04 14:42:52 +0200400
401 // ADJUST CROP HEIGHT
402 if (isPortrait) {
Michael Jurka454db972013-10-31 16:32:43 +0100403 cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale;
Michael Jurka2d8de582013-09-04 14:42:52 +0200404 } else { // LANDSCAPE
405 float extraPortraitHeight =
Michael Jurka454db972013-10-31 16:32:43 +0100406 defaultWallpaperSize.y / cropScale - cropRect.height();
Michael Jurka2d8de582013-09-04 14:42:52 +0200407 float expandHeight =
Michael Jurka8713a942013-10-10 21:28:40 -0700408 Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
Michael Jurka2d8de582013-09-04 14:42:52 +0200409 extraPortraitHeight / 2);
410 cropRect.top -= expandHeight;
411 cropRect.bottom += expandHeight;
412 }
413 final int outWidth = (int) Math.round(cropRect.width() * cropScale);
414 final int outHeight = (int) Math.round(cropRect.height() * cropScale);
415
416 Runnable onEndCrop = new Runnable() {
417 public void run() {
418 updateWallpaperDimensions(outWidth, outHeight);
419 if (finishActivityWhenDone) {
420 setResult(Activity.RESULT_OK);
421 finish();
422 }
423 }
424 };
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700425 BitmapCropTask cropTask = new BitmapCropTask(getContext(), uri,
Michael Jurka8713a942013-10-10 21:28:40 -0700426 cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
Michael Jurkabe2f8dd2013-09-10 13:39:59 +0200427 if (onBitmapCroppedHandler != null) {
428 cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
429 }
Michael Jurka2d8de582013-09-04 14:42:52 +0200430 cropTask.execute();
431 }
Michael Jurka104c4562013-07-08 18:03:46 -0700432
Michael Jurka104c4562013-07-08 18:03:46 -0700433 protected void updateWallpaperDimensions(int width, int height) {
Sunny Goyal6a1e95a2015-03-20 17:26:30 -0700434 String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY;
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700435 SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
Michael Jurka104c4562013-07-08 18:03:46 -0700436 SharedPreferences.Editor editor = sp.edit();
437 if (width != 0 && height != 0) {
438 editor.putInt(WALLPAPER_WIDTH_KEY, width);
439 editor.putInt(WALLPAPER_HEIGHT_KEY, height);
440 } else {
441 editor.remove(WALLPAPER_WIDTH_KEY);
442 editor.remove(WALLPAPER_HEIGHT_KEY);
443 }
444 editor.commit();
Sunny Goyal6a1e95a2015-03-20 17:26:30 -0700445 WallpaperUtils.suggestWallpaperDimension(getResources(),
Sunny Goyal1d0b0932015-03-20 18:51:38 -0700446 sp, getWindowManager(), WallpaperManager.getInstance(getContext()), true);
Michael Jurka104c4562013-07-08 18:03:46 -0700447 }
448
Sunny Goyal65b929d2015-02-12 15:34:41 -0800449 static class LoadRequest {
450 BitmapSource src;
451 boolean touchEnabled;
452 boolean moveToLeft;
453 Runnable postExecute;
454 CropViewScaleProvider scaleProvider;
455
456 TileSource result;
457 }
458
459 interface CropViewScaleProvider {
460 float getScale(TileSource src);
461 }
Michael Jurka104c4562013-07-08 18:03:46 -0700462}