1 /*
2  * Copyright (C) 2010 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 
17 package com.android.gallery3d.ui;
18 
19 import android.graphics.Bitmap;
20 
21 import com.android.photos.data.GalleryBitmapPool;
22 import com.android.gallery3d.util.Future;
23 import com.android.gallery3d.util.FutureListener;
24 
25 // We use this class to
26 //     1.) load bitmaps in background.
27 //     2.) as a place holder for the loaded bitmap
28 public abstract class BitmapLoader implements FutureListener<Bitmap> {
29     @SuppressWarnings("unused")
30     private static final String TAG = "BitmapLoader";
31 
32     /* Transition Map:
33      *   INIT -> REQUESTED, RECYCLED
34      *   REQUESTED -> INIT (cancel), LOADED, ERROR, RECYCLED
35      *   LOADED, ERROR -> RECYCLED
36      */
37     private static final int STATE_INIT = 0;
38     private static final int STATE_REQUESTED = 1;
39     private static final int STATE_LOADED = 2;
40     private static final int STATE_ERROR = 3;
41     private static final int STATE_RECYCLED = 4;
42 
43     private int mState = STATE_INIT;
44     // mTask is not null only when a task is on the way
45     private Future<Bitmap> mTask;
46     private Bitmap mBitmap;
47 
48     @Override
onFutureDone(Future<Bitmap> future)49     public void onFutureDone(Future<Bitmap> future) {
50         synchronized (this) {
51             mTask = null;
52             mBitmap = future.get();
53             if (mState == STATE_RECYCLED) {
54                 if (mBitmap != null) {
55                     GalleryBitmapPool.getInstance().put(mBitmap);
56                     mBitmap = null;
57                 }
58                 return; // don't call callback
59             }
60             if (future.isCancelled() && mBitmap == null) {
61                 if (mState == STATE_REQUESTED) mTask = submitBitmapTask(this);
62                 return; // don't call callback
63             } else {
64                 mState = mBitmap == null ? STATE_ERROR : STATE_LOADED;
65             }
66         }
67         onLoadComplete(mBitmap);
68     }
69 
startLoad()70     public synchronized void startLoad() {
71         if (mState == STATE_INIT) {
72             mState = STATE_REQUESTED;
73             if (mTask == null) mTask = submitBitmapTask(this);
74         }
75     }
76 
cancelLoad()77     public synchronized void cancelLoad() {
78         if (mState == STATE_REQUESTED) {
79             mState = STATE_INIT;
80             if (mTask != null) mTask.cancel();
81         }
82     }
83 
84     // Recycle the loader and the bitmap
recycle()85     public synchronized void recycle() {
86         mState = STATE_RECYCLED;
87         if (mBitmap != null) {
88             GalleryBitmapPool.getInstance().put(mBitmap);
89             mBitmap = null;
90         }
91         if (mTask != null) mTask.cancel();
92     }
93 
isRequestInProgress()94     public synchronized boolean isRequestInProgress() {
95         return mState == STATE_REQUESTED;
96     }
97 
isRecycled()98     public synchronized boolean isRecycled() {
99         return mState == STATE_RECYCLED;
100     }
101 
getBitmap()102     public synchronized Bitmap getBitmap() {
103         return mBitmap;
104     }
105 
submitBitmapTask(FutureListener<Bitmap> l)106     abstract protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l);
onLoadComplete(Bitmap bitmap)107     abstract protected void onLoadComplete(Bitmap bitmap);
108 }
109