diff options
author | Owen Lin <owenlin@google.com> | 2009-04-20 15:59:57 +0800 |
---|---|---|
committer | Owen Lin <owenlin@google.com> | 2009-04-29 22:45:36 -0700 |
commit | 41a8578529dedf1e81218d4429954d6ccd9d67af (patch) | |
tree | b78fc2d6b02fc5c06aae5e1eab8773867905eb80 /src/com/android | |
parent | 208ec6d4e4211504975404e6af22d6be7c03085d (diff) | |
download | LegacyCamera-41a8578529dedf1e81218d4429954d6ccd9d67af.zip LegacyCamera-41a8578529dedf1e81218d4429954d6ccd9d67af.tar.gz LegacyCamera-41a8578529dedf1e81218d4429954d6ccd9d67af.tar.bz2 |
Improve the design of ICancelable.
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/camera/Camera.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/CropImage.java | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | src/com/android/camera/ImageManager.java | 62 | ||||
-rw-r--r-- | src/com/android/camera/PriorityTask.java | 13 | ||||
-rw-r--r-- | src/com/android/camera/ViewImage.java | 39 | ||||
-rw-r--r-- | src/com/android/camera/gallery/BaseCancelable.java | 177 | ||||
-rw-r--r-- | src/com/android/camera/gallery/BaseImage.java | 33 | ||||
-rw-r--r-- | src/com/android/camera/gallery/Cancelable.java | 56 | ||||
-rw-r--r-- | src/com/android/camera/gallery/CanceledException.java | 23 | ||||
-rw-r--r-- | src/com/android/camera/gallery/ICancelable.java | 32 | ||||
-rw-r--r-- | src/com/android/camera/gallery/IImage.java | 2 | ||||
-rw-r--r-- | src/com/android/camera/gallery/Image.java | 106 | ||||
-rw-r--r-- | src/com/android/camera/gallery/UriImage.java | 16 | ||||
-rw-r--r-- | src/com/android/camera/gallery/VideoObject.java | 2 |
14 files changed, 329 insertions, 240 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 2167b2a..fe1af38 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -16,7 +16,7 @@ package com.android.camera; -import com.android.camera.gallery.ICancelable; +import com.android.camera.gallery.Cancelable; import com.android.camera.gallery.IImage; import com.android.camera.gallery.IImageList; @@ -458,7 +458,7 @@ public class Camera extends Activity implements View.OnClickListener, private boolean mCapturing = false; private Uri mLastContentUri; - private ICancelable<Void> mAddImageCancelable; + private Cancelable<Void> mAddImageCancelable; Bitmap mCaptureOnlyBitmap; diff --git a/src/com/android/camera/CropImage.java b/src/com/android/camera/CropImage.java index 99817ac..a64b02c 100644 --- a/src/com/android/camera/CropImage.java +++ b/src/com/android/camera/CropImage.java @@ -16,7 +16,7 @@ package com.android.camera; -import com.android.camera.gallery.ICancelable; +import com.android.camera.gallery.Cancelable; import com.android.camera.gallery.IImage; import com.android.camera.gallery.IImageList; @@ -374,7 +374,7 @@ public class CropImage extends Activity { directory.toString(), fileName + "-" + x + ".jpg"); - ICancelable<Void> cancelable = + Cancelable<Void> cancelable = ImageManager.storeImage( newUri, getContentResolver(), diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index cbf025e..e936824 100644..100755 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -18,9 +18,8 @@ package com.android.camera; import com.android.camera.gallery.BaseCancelable; import com.android.camera.gallery.BaseImageList; -import com.android.camera.gallery.CanceledException; +import com.android.camera.gallery.Cancelable; import com.android.camera.gallery.DrmImageList; -import com.android.camera.gallery.ICancelable; import com.android.camera.gallery.IImage; import com.android.camera.gallery.IImageList; import com.android.camera.gallery.Image; @@ -47,6 +46,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.ExecutionException; /** * ImageManager is used to retrieve and store images @@ -54,7 +54,6 @@ import java.util.HashMap; */ public class ImageManager { private static final String TAG = "ImageManager"; - private static ImageManager sInstance = null; private static final Uri STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI; private static final Uri THUMB_URI @@ -202,7 +201,6 @@ public class ImageManager { } private static class AddImageCancelable extends BaseCancelable<Void> { - private ICancelable<Boolean> mSaveImageCancelable; private final Uri mUri; private final ContentResolver mCr; private final int mOrientation; @@ -211,7 +209,7 @@ public class ImageManager { public AddImageCancelable(Uri uri, ContentResolver cr, int orientation, Bitmap source, byte[] jpegData) { - if (source == null && jpegData == null) { + if (source == null && jpegData == null || uri == null) { throw new IllegalArgumentException("source cannot be null"); } mUri = uri; @@ -222,60 +220,46 @@ public class ImageManager { } @Override - public boolean doCancelWork() { - if (mSaveImageCancelable != null) { - mSaveImageCancelable.cancel(); - } - return true; - } - - public Void get() { + protected Void execute() throws InterruptedException, + ExecutionException { + boolean complete = false; try { - synchronized (this) { - if (mCancel) { - throw new CanceledException(); - } - } long id = ContentUris.parseId(mUri); - BaseImageList il = new ImageList(mCr, STORAGE_URI, THUMB_URI, SORT_ASCENDING, null); Image image = new Image(id, 0, mCr, il, il.getCount(), 0); String[] projection = new String[] { ImageColumns._ID, ImageColumns.MINI_THUMB_MAGIC, ImageColumns.DATA}; - Cursor c = mCr.query(mUri, projection, null, null, null); + String filepath; try { c.moveToPosition(0); - synchronized (this) { - checkCanceled(); - mSaveImageCancelable = image.saveImageContents( - mSource, mJpegData, mOrientation, true, - c.getString(2)); - } + filepath = c.getString(2); } finally { c.close(); } + runSubTask(image.saveImageContents( + mSource, mJpegData, mOrientation, true, filepath)); - if (mSaveImageCancelable.get()) { - ContentValues values = new ContentValues(); - values.put(ImageColumns.MINI_THUMB_MAGIC, 0); - mCr.update(mUri, values, null, null); - } else { - throw new CanceledException(); - } - } catch (CanceledException ex) { - if (mUri != null) { - mCr.delete(mUri, null, null); + ContentValues values = new ContentValues(); + values.put(ImageColumns.MINI_THUMB_MAGIC, 0); + mCr.update(mUri, values, null, null); + complete = true; + return null; + } finally { + if (!complete) { + try { + mCr.delete(mUri, null, null); + } catch (Throwable t) { + // ignore it while clean up. + } } - acknowledgeCancel(); } - return null; } } - public static ICancelable<Void> storeImage( + public static Cancelable<Void> storeImage( Uri uri, ContentResolver cr, int orientation, Bitmap source, byte [] jpegData) { return new AddImageCancelable( diff --git a/src/com/android/camera/PriorityTask.java b/src/com/android/camera/PriorityTask.java index db8ed3c..a060071 100644 --- a/src/com/android/camera/PriorityTask.java +++ b/src/com/android/camera/PriorityTask.java @@ -16,6 +16,8 @@ package com.android.camera; +import com.android.camera.gallery.Cancelable; + import android.os.SystemClock; import android.util.Log; @@ -33,7 +35,7 @@ import java.util.concurrent.atomic.AtomicLong; * @param <T> the type of the return value. */ public abstract class PriorityTask<T> - implements Runnable, Comparable<PriorityTask<?>> { + implements Cancelable<T>, Runnable, Comparable<PriorityTask<?>> { private static final String TAG = "PriorityTask"; private static final int STATE_INITIAL = (1 << 0); @@ -173,9 +175,8 @@ public abstract class PriorityTask<T> /** * Requests the task to be canceled. * - * @return true if the task has not been canceled but will be canceled; - * false otherwise (usually the task has been complete/failed/ - * canceled. + * @return true if the task is running and has not been requested for + * cancel. */ public synchronized boolean requestCancel() { if (mState == STATE_EXECUTING) { @@ -285,6 +286,10 @@ public abstract class PriorityTask<T> return true; } + public synchronized void await() throws InterruptedException { + await(0); + } + // used only by PriorityTaskQueue#remove void resetState() { mState = STATE_INITIAL; diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java index 0d44e09..8053151 100644 --- a/src/com/android/camera/ViewImage.java +++ b/src/com/android/camera/ViewImage.java @@ -16,7 +16,7 @@ package com.android.camera; -import com.android.camera.gallery.ICancelable; +import com.android.camera.gallery.Cancelable; import com.android.camera.gallery.IImage; import com.android.camera.gallery.IImageList; @@ -50,6 +50,8 @@ import android.widget.Toast; import android.widget.ZoomButtonsController; import java.util.Random; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; // This activity can display a whole picture and navigate them in a specific // gallery. It has two modes: normal mode and slide show mode. In normal mode @@ -68,7 +70,7 @@ public class ViewImage extends Activity implements View.OnClickListener { LocalHandler mHandler = new LocalHandler(); - private Random mRandom = new Random(System.currentTimeMillis()); + private final Random mRandom = new Random(System.currentTimeMillis()); private int [] mShuffleOrder; private boolean mUseShuffleOrder = false; private boolean mSlideShowLoop = false; @@ -94,10 +96,10 @@ public class ViewImage extends Activity implements View.OnClickListener { private SharedPreferences mPrefs; private View mNextImageView, mPrevImageView; - private Animation mHideNextImageViewAnimation = new AlphaAnimation(1F, 0F); - private Animation mHidePrevImageViewAnimation = new AlphaAnimation(1F, 0F); - private Animation mShowNextImageViewAnimation = new AlphaAnimation(0F, 1F); - private Animation mShowPrevImageViewAnimation = new AlphaAnimation(0F, 1F); + private final Animation mHideNextImageViewAnimation = new AlphaAnimation(1F, 0F); + private final Animation mHidePrevImageViewAnimation = new AlphaAnimation(1F, 0F); + private final Animation mShowNextImageViewAnimation = new AlphaAnimation(0F, 1F); + private final Animation mShowPrevImageViewAnimation = new AlphaAnimation(0F, 1F); static final int PADDING = 20; static final int HYSTERESIS = PADDING * 2; @@ -106,7 +108,7 @@ public class ViewImage extends Activity implements View.OnClickListener { IImageList mAllImages; private int mSlideShowImageCurrent = 0; - private ImageViewTouchBase [] mSlideShowImageViews = + private final ImageViewTouchBase [] mSlideShowImageViews = new ImageViewTouchBase[2]; GestureDetector mGestureDetector; @@ -1079,7 +1081,7 @@ public class ViewImage extends Activity implements View.OnClickListener { } class ImageViewTouch extends ImageViewTouchBase { - private ViewImage mViewImage; + private final ViewImage mViewImage; private boolean mEnableTrackballScroll; public ImageViewTouch(Context context) { @@ -1239,7 +1241,7 @@ class ImageGetter { private static final String TAG = "ImageGetter"; // The thread which does the work. - private Thread mGetterThread; + private final Thread mGetterThread; // The base position that's being retrieved. The actual images retrieved // are this base plus each of the offets. @@ -1250,7 +1252,7 @@ class ImageGetter { // This is the loader cancelable that gets set while we're loading an image. // If we change position we can cancel the current load using this. - private ICancelable<Bitmap> mLoad; + private Cancelable<Bitmap> mLoad; // True if we're canceling the current load. private boolean mCancelCurrent = false; @@ -1268,9 +1270,9 @@ class ImageGetter { synchronized (this) { if (!mReady) { mCancelCurrent = true; - ICancelable<Bitmap> load = mLoad; + Cancelable<Bitmap> load = mLoad; if (load != null) { - load.cancel(); + load.requestCancel(); } mCancelCurrent = false; } @@ -1359,7 +1361,16 @@ class ImageGetter { if (mLoad != null) { // The return value could be null if the // bitmap is too big, or we cancelled it. - Bitmap b = mLoad.get(); + Bitmap b; + try { + b = mLoad.get(); + } catch (InterruptedException e) { + b = null; + } catch (ExecutionException e) { + throw new RuntimeException(e); + } catch (CancellationException e) { + b = null; + } mLoad = null; if (b != null) { if (isCanceled()) { @@ -1452,7 +1463,7 @@ class BitmapCache implements ImageViewTouchBase.Recycler { } } - private Entry[] mCache; + private final Entry[] mCache; public BitmapCache(int size) { mCache = new Entry[size]; diff --git a/src/com/android/camera/gallery/BaseCancelable.java b/src/com/android/camera/gallery/BaseCancelable.java index 9b9bf68..fd9779f 100644 --- a/src/com/android/camera/gallery/BaseCancelable.java +++ b/src/com/android/camera/gallery/BaseCancelable.java @@ -16,53 +16,164 @@ package com.android.camera.gallery; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + /** - * A base class for the interface <code>ICancelable</code>. + * An abstract class for the interface <code>Cancelable</code>. Subclass can + * simply override the <code>execute()</code> function to provide an + * implementation of <code>Cancelable</code>. */ -public abstract class BaseCancelable<T> implements ICancelable<T> { - protected boolean mCancel = false; - protected boolean mFinished = false; +public abstract class BaseCancelable<T> implements Cancelable<T> { - /* - * Subclasses should call acknowledgeCancel when they're finished with - * their operation. + /** + * The state of the task, possible transitions are: + * <pre> + * INITIAL -> CANCELED + * EXECUTING -> COMPLETE, CANCELING, ERROR, CANCELED + * CANCELING -> CANCELED + * </pre> + * When the task stop, it must be end with one of the following states: + * COMPLETE, CANCELED, or ERROR; */ - protected synchronized void acknowledgeCancel() { - mFinished = true; - if (mCancel) { - this.notify(); + private static final int STATE_INITIAL = (1 << 0); + private static final int STATE_EXECUTING = (1 << 1); + private static final int STATE_CANCELING = (1 << 2); + private static final int STATE_CANCELED = (1 << 3); + private static final int STATE_ERROR = (1 << 4); + private static final int STATE_COMPLETE = (1 << 5); + + private int mState = STATE_INITIAL; + + private Throwable mError; + private T mResult; + private Cancelable<?> mCurrentTask; + private Thread mThread; + + protected abstract T execute() throws Exception; + + protected synchronized void interruptNow() { + if (isInStates(STATE_CANCELING | STATE_EXECUTING)) { + mThread.interrupt(); } } - public synchronized boolean cancel() { - if (mCancel || mFinished) { - return false; + /** + * Frees the result (which is not null) when the task has been canceled. + */ + protected void freeCanceledResult(T result) { + // Do nothing by default; + } + + private boolean isInStates(int states) { + return (states & mState) != 0; + } + + private T handleTerminalStates() throws ExecutionException { + if (mState == STATE_CANCELED) { + throw new CancellationException(); + } + if (mState == STATE_ERROR) { + throw new ExecutionException(mError); + } + if (mState == STATE_COMPLETE) return mResult; + throw new IllegalStateException(); + } + + public synchronized void await() throws InterruptedException { + while (!isInStates(STATE_COMPLETE | STATE_CANCELED | STATE_ERROR)) { + wait(); + } + } + + public final T get() throws InterruptedException, ExecutionException { + synchronized (this) { + if (mState != STATE_INITIAL) { + await(); + return handleTerminalStates(); + } + mThread = Thread.currentThread(); + mState = STATE_EXECUTING; } - mCancel = true; - boolean retVal = doCancelWork(); try { - this.wait(); - } catch (InterruptedException ex) { - throw new RuntimeException(ex); + mResult = execute(); + } catch (CancellationException e) { + mState = STATE_CANCELED; + } catch (InterruptedException e) { + mState = STATE_CANCELED; + } catch (Throwable error) { + synchronized (this) { + if (mState != STATE_CANCELING) { + mError = error; + mState = STATE_ERROR; + } + } + } + synchronized (this) { + if (mState == STATE_CANCELING) mState = STATE_CANCELED; + if (mState == STATE_EXECUTING) mState = STATE_COMPLETE; + notifyAll(); + if (mState == STATE_CANCELED && mResult != null) { + freeCanceledResult(mResult); + } + return handleTerminalStates(); } - return retVal; } - /* - * Subclasses can call this to see if they have been canceled. - * This is the polling model. + /** + * Requests the task to be canceled. + * + * @return true if the task is running and has not been canceled; false + * otherwise */ - protected synchronized void checkCanceled() throws CanceledException { - if (mCancel) { - throw new CanceledException(); + + public synchronized boolean requestCancel() { + if (mState == STATE_INITIAL) { + mState = STATE_CANCELED; + notifyAll(); + return false; } + if (mState == STATE_EXECUTING) { + if (mCurrentTask != null) mCurrentTask.requestCancel(); + mState = STATE_CANCELING; + return true; + } + return false; } - /* - * Subclasses implement this method to take whatever action - * is necessary when getting canceled. Sometimes it's not - * possible to do anything in which case the "checkCanceled" - * polling model may be used (or some combination). + /** + * Whether the task's has been requested for cancel. */ - protected abstract boolean doCancelWork(); -}
\ No newline at end of file + protected synchronized boolean isCanceling() { + return mState == STATE_CANCELING; + } + + /** + * Runs a <code>Cancelable</code> subtask. This method is helpful, if the + * task can be composed of several cancelable tasks. By using this function, + * it will pass <code>requestCancel</code> message to those subtasks. + * + * @param <T> the return type of the sub task + * @param cancelable the sub task + * @return the result of the subtask + */ + protected <T> T runSubTask(Cancelable<T> cancelable) + throws InterruptedException, ExecutionException { + synchronized (this) { + if (mCurrentTask != null) { + throw new IllegalStateException( + "cannot two subtasks at the same time"); + } + if (mState == STATE_CANCELING) throw new CancellationException(); + mCurrentTask = cancelable; + } + try { + return cancelable.get(); + } finally { + synchronized (this) { + mCurrentTask = null; + } + } + } + +} diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java index 4bd542a..fbb7239 100644 --- a/src/com/android/camera/gallery/BaseImage.java +++ b/src/com/android/camera/gallery/BaseImage.java @@ -80,19 +80,21 @@ public abstract class BaseImage implements IImage { } @Override - public boolean doCancelWork() { - if (mOutputStream != null) { - mOutputStream.close(); + public boolean requestCancel() { + if (super.requestCancel()) { + if (mOutputStream != null) { + mOutputStream.close(); + } return true; } return false; } - public Boolean get() { + @Override + public Boolean execute() { try { OutputStream delegate = mContentResolver.openOutputStream(mUri); synchronized (this) { - checkCanceled(); mOutputStream = new ThreadSafeOutputStream(delegate); } if (mBitmap != null) { @@ -103,13 +105,10 @@ public abstract class BaseImage implements IImage { return true; } catch (FileNotFoundException ex) { return false; - } catch (CanceledException ex) { - return false; } catch (IOException ex) { return false; } finally { Util.closeSiliently(mOutputStream); - acknowledgeCancel(); } } } @@ -122,7 +121,7 @@ public abstract class BaseImage implements IImage { * @param uri where to store the bitmap * @return true if we succeeded */ - protected ICancelable<Boolean> compressImageToFile( + protected Cancelable<Boolean> compressImageToFile( Bitmap bitmap, byte [] jpegData, Uri uri) { return new CompressImageToFile(bitmap, jpegData, uri); } @@ -167,12 +166,16 @@ public abstract class BaseImage implements IImage { } @Override - public boolean doCancelWork() { - mOptions.requestCancelDecode(); - return true; + public boolean requestCancel() { + if (super.requestCancel()) { + mOptions.requestCancelDecode(); + return true; + } + return false; } - public Bitmap get() { + @Override + protected Bitmap execute() { try { Bitmap b = Util.makeBitmap( mTargetWidthHeight, fullSizeImageUri(), @@ -185,14 +188,12 @@ public abstract class BaseImage implements IImage { return null; } catch (Error e) { return null; - } finally { - acknowledgeCancel(); } } } - public ICancelable<Bitmap> fullSizeBitmapCancelable( + public Cancelable<Bitmap> fullSizeBitmapCancelable( int targetWidthHeight) { try { ParcelFileDescriptor pfdInput = mContentResolver diff --git a/src/com/android/camera/gallery/Cancelable.java b/src/com/android/camera/gallery/Cancelable.java new file mode 100644 index 0000000..79a7d1b --- /dev/null +++ b/src/com/android/camera/gallery/Cancelable.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.gallery; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + +/** + * The interface for all the tasks that could be canceled. + */ +public interface Cancelable<T> { + /* + * Requests this <code>Cancelable</code> to be canceled. This function will + * return <code>true</code> if and only if the task is originally running + * and now begin requested for cancel. + * + * If subclass need to do more things to cancel the task. It can override + * the code like this: + * <pre> + * @Override + * public boolean requestCancel() { + * if (super.requestCancel()) { + * // do necessary work to cancel the task + * return true; + * } + * return false; + * } + * </pre> + */ + public boolean requestCancel(); + + public void await() throws InterruptedException; + + /** + * Gets the results of this <code>Cancelable</code> task. + * + * @throws CancellationException if the task has been cancelled + * @throws ExecutionException if exception is thrown during the execution of + * the task + */ + public T get() throws InterruptedException, ExecutionException; +}
\ No newline at end of file diff --git a/src/com/android/camera/gallery/CanceledException.java b/src/com/android/camera/gallery/CanceledException.java deleted file mode 100644 index 5daa48c..0000000 --- a/src/com/android/camera/gallery/CanceledException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera.gallery; - -/** - * Exception which will be thrown when the task has been canceled. - */ -public class CanceledException extends Exception { -}
\ No newline at end of file diff --git a/src/com/android/camera/gallery/ICancelable.java b/src/com/android/camera/gallery/ICancelable.java deleted file mode 100644 index 9c9e1bf..0000000 --- a/src/com/android/camera/gallery/ICancelable.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera.gallery; - -/** - * The interface for all the tasks that could be canceled. - */ -public interface ICancelable<T> { - /* - * call cancel() when the unit of work in progress needs to be - * canceled. This should return true if it was possible to - * cancel and false otherwise. If this returns false the caller - * may still be able to cleanup and simulate cancelation. - */ - public boolean cancel(); - - public T get(); -}
\ No newline at end of file diff --git a/src/com/android/camera/gallery/IImage.java b/src/com/android/camera/gallery/IImage.java index 921f40b..9c47d13 100644 --- a/src/com/android/camera/gallery/IImage.java +++ b/src/com/android/camera/gallery/IImage.java @@ -35,7 +35,7 @@ public interface IImage { public abstract Bitmap fullSizeBitmap(int targetWidthOrHeight); /** Get the cancelable object for the bitmap of the full size image. */ - public abstract ICancelable<Bitmap> fullSizeBitmapCancelable( + public abstract Cancelable<Bitmap> fullSizeBitmapCancelable( int targetWidthOrHeight); /** Get the input stream associated with a given full size image. */ diff --git a/src/com/android/camera/gallery/Image.java b/src/com/android/camera/gallery/Image.java index 2d60a47..58d9948 100644 --- a/src/com/android/camera/gallery/Image.java +++ b/src/com/android/camera/gallery/Image.java @@ -33,6 +33,7 @@ import android.util.Log; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.concurrent.ExecutionException; /** * The class for normal images in gallery. @@ -171,12 +172,11 @@ public class Image extends BaseImage implements IImage { mExifData.put(tag, value); } - private class SaveImageContentsCancelable extends BaseCancelable<Boolean> { + private class SaveImageContentsCancelable extends BaseCancelable<Void> { private final Bitmap mImage; private final byte [] mJpegData; private final int mOrientation; private final String mFilePath; - ICancelable<Boolean> mCurrentCancelable = null; SaveImageContentsCancelable(Bitmap image, byte[] jpegData, int orientation, String filePath) { @@ -187,80 +187,54 @@ public class Image extends BaseImage implements IImage { } @Override - public boolean doCancelWork() { - synchronized (this) { - if (mCurrentCancelable != null) mCurrentCancelable.cancel(); - } - return true; - } + public Void execute() throws InterruptedException, ExecutionException { + Bitmap thumbnail = null; + Uri uri = mContainer.contentUri(mId); + runSubTask(compressImageToFile(mImage, mJpegData, uri)); - public Boolean get() { - try { - Bitmap thumbnail = null; - - Uri uri = mContainer.contentUri(mId); - synchronized (this) { - checkCanceled(); - mCurrentCancelable = - compressImageToFile(mImage, mJpegData, uri); + synchronized (this) { + String filePath = mFilePath; + + // TODO: If thumbData is present and usable, we should call + // the version of storeThumbnail which takes a byte array, + // rather than re-encoding a new JPEG of the same + // dimensions. + byte[] thumbData = null; + synchronized (ExifInterface.class) { + thumbData = + (new ExifInterface(filePath)).getThumbnail(); } - if (!mCurrentCancelable.get()) return false; - - synchronized (this) { - String filePath = mFilePath; - - // TODO: If thumbData is present and usable, we should call - // the version of storeThumbnail which takes a byte array, - // rather than re-encoding a new JPEG of the same - // dimensions. - byte[] thumbData = null; - synchronized (ExifInterface.class) { - thumbData = - (new ExifInterface(filePath)).getThumbnail(); - } - - if (thumbData != null) { - thumbnail = BitmapFactory.decodeByteArray( - thumbData, 0, thumbData.length); - } - if (thumbnail == null && mImage != null) { - thumbnail = mImage; - } - if (thumbnail == null && mJpegData != null) { - thumbnail = BitmapFactory.decodeByteArray( - mJpegData, 0, mJpegData.length); - } + if (thumbData != null) { + thumbnail = BitmapFactory.decodeByteArray( + thumbData, 0, thumbData.length); } + if (thumbnail == null && mImage != null) { + thumbnail = mImage; + } + if (thumbnail == null && mJpegData != null) { + thumbnail = BitmapFactory.decodeByteArray( + mJpegData, 0, mJpegData.length); + } + } - mContainer.storeThumbnail( - thumbnail, Image.this.fullSizeImageId()); - checkCanceled(); + mContainer.storeThumbnail( + thumbnail, Image.this.fullSizeImageId()); + if (isCanceling()) return null; - try { - thumbnail = Util.rotate(thumbnail, mOrientation); - saveMiniThumb(thumbnail); - } catch (IOException e) { - // Ignore if unable to save thumb. - } - checkCanceled(); - return true; - } catch (CanceledException ex) { - // Got canceled... need to cleanup. - return false; - } finally { - /* - * Cursor c = getCursor(); synchronized (c) { if - * (c.moveTo(getRow())) { mContainer.requery(); } } - */ - acknowledgeCancel(); + try { + thumbnail = Util.rotate(thumbnail, mOrientation); + saveMiniThumb(thumbnail); + } catch (IOException e) { + // Ignore if unable to save thumb. + Log.e(TAG, "unable to rotate / save thumb", e); } + return null; } } - public ICancelable<Boolean> saveImageContents(Bitmap image, - byte [] jpegData, int orientation, boolean newFile, - String filePath) { + public Cancelable<Void> saveImageContents(Bitmap image, byte [] jpegData, + int orientation, boolean newFile, String filePath) { return new SaveImageContentsCancelable( image, jpegData, orientation, filePath); } diff --git a/src/com/android/camera/gallery/UriImage.java b/src/com/android/camera/gallery/UriImage.java index dddde36..0232a90 100644 --- a/src/com/android/camera/gallery/UriImage.java +++ b/src/com/android/camera/gallery/UriImage.java @@ -112,12 +112,16 @@ class UriImage implements IImage { } @Override - public boolean doCancelWork() { - mOptions.requestCancelDecode(); - return true; + public boolean requestCancel() { + if (super.requestCancel()) { + mOptions.requestCancelDecode(); + return true; + } + return false; } - public Bitmap get() { + @Override + protected Bitmap execute() { try { Bitmap b = Util.makeBitmap(mTargetWidthOrHeight, fullSizeImageUri(), mContentResolver, mPfdInput, @@ -125,13 +129,11 @@ class UriImage implements IImage { return b; } catch (Exception ex) { return null; - } finally { - acknowledgeCancel(); } } } - public ICancelable<Bitmap> fullSizeBitmapCancelable( + public Cancelable<Bitmap> fullSizeBitmapCancelable( int targetWidthOrHeight) { try { ParcelFileDescriptor pfdInput = getPFD(); diff --git a/src/com/android/camera/gallery/VideoObject.java b/src/com/android/camera/gallery/VideoObject.java index 25d62d7..a5ed17e 100644 --- a/src/com/android/camera/gallery/VideoObject.java +++ b/src/com/android/camera/gallery/VideoObject.java @@ -78,7 +78,7 @@ public class VideoObject extends BaseImage implements IImage { } @Override - public ICancelable<Bitmap> fullSizeBitmapCancelable( + public Cancelable<Bitmap> fullSizeBitmapCancelable( int targetWidthHeight) { return null; } |