fedilab-Android-App/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapLoadingWorkerTask.java

177 lines
4.8 KiB
Java

// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they begin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
//
// - Sun Tsu,
// "The Art of War"
package com.theartofdev.edmodo.cropper;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.DisplayMetrics;
import java.lang.ref.WeakReference;
/**
* Task to load bitmap asynchronously from the UI thread.
*/
final class BitmapLoadingWorkerTask extends AsyncTask<Void, Void, BitmapLoadingWorkerTask.Result> {
// region: Fields and Consts
/**
* Use a WeakReference to ensure the ImageView can be garbage collected
*/
private final WeakReference<CropImageView> mCropImageViewReference;
/**
* The Android URI of the image to load
*/
private final Uri mUri;
/**
* The context of the crop image view widget used for loading of bitmap by Android URI
*/
private final Context mContext;
/**
* required width of the cropping image after density adjustment
*/
private final int mWidth;
/**
* required height of the cropping image after density adjustment
*/
private final int mHeight;
// endregion
public BitmapLoadingWorkerTask(CropImageView cropImageView, Uri uri) {
mUri = uri;
mCropImageViewReference = new WeakReference<>(cropImageView);
mContext = cropImageView.getContext();
DisplayMetrics metrics = cropImageView.getResources().getDisplayMetrics();
double densityAdj = metrics.density > 1 ? 1 / metrics.density : 1;
mWidth = (int) (metrics.widthPixels * densityAdj);
mHeight = (int) (metrics.heightPixels * densityAdj);
}
/**
* The Android URI that this task is currently loading.
*/
public Uri getUri() {
return mUri;
}
/**
* Decode image in background.
*
* @param params ignored
* @return the decoded bitmap data
*/
@Override
protected Result doInBackground(Void... params) {
try {
if (!isCancelled()) {
BitmapUtils.BitmapSampled decodeResult =
BitmapUtils.decodeSampledBitmap(mContext, mUri, mWidth, mHeight);
if (!isCancelled()) {
BitmapUtils.RotateBitmapResult rotateResult =
BitmapUtils.rotateBitmapByExif(decodeResult.bitmap, mContext, mUri);
return new Result(
mUri, rotateResult.bitmap, decodeResult.sampleSize, rotateResult.degrees);
}
}
return null;
} catch (Exception e) {
return new Result(mUri, e);
}
}
/**
* Once complete, see if ImageView is still around and set bitmap.
*
* @param result the result of bitmap loading
*/
@Override
protected void onPostExecute(Result result) {
if (result != null) {
boolean completeCalled = false;
if (!isCancelled()) {
CropImageView cropImageView = mCropImageViewReference.get();
if (cropImageView != null) {
completeCalled = true;
cropImageView.onSetImageUriAsyncComplete(result);
}
}
if (!completeCalled && result.bitmap != null) {
// fast release of unused bitmap
result.bitmap.recycle();
}
}
}
// region: Inner class: Result
/**
* The result of BitmapLoadingWorkerTask async loading.
*/
public static final class Result {
/**
* The Android URI of the image to load
*/
public final Uri uri;
/**
* The loaded bitmap
*/
public final Bitmap bitmap;
/**
* The sample size used to load the given bitmap
*/
public final int loadSampleSize;
/**
* The degrees the image was rotated
*/
public final int degreesRotated;
/**
* The error that occurred during async bitmap loading.
*/
public final Exception error;
Result(Uri uri, Bitmap bitmap, int loadSampleSize, int degreesRotated) {
this.uri = uri;
this.bitmap = bitmap;
this.loadSampleSize = loadSampleSize;
this.degreesRotated = degreesRotated;
this.error = null;
}
Result(Uri uri, Exception error) {
this.uri = uri;
this.bitmap = null;
this.loadSampleSize = 0;
this.degreesRotated = 0;
this.error = error;
}
}
// endregion
}