SinglePhotoDataAdapter.java revision d9355113da391f8bbddef1d2a2126ce6edc72291
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
17package com.android.gallery3d.app;
18
19import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.graphics.BitmapRegionDecoder;
22import android.graphics.Rect;
23import android.os.Handler;
24import android.os.Message;
25
26import com.android.gallery3d.common.BitmapUtils;
27import com.android.gallery3d.common.Utils;
28import com.android.gallery3d.data.MediaItem;
29import com.android.gallery3d.data.Path;
30import com.android.gallery3d.ui.PhotoView;
31import com.android.gallery3d.ui.ScreenNail;
32import com.android.gallery3d.ui.SynchronizedHandler;
33import com.android.gallery3d.ui.TileImageViewAdapter;
34import com.android.gallery3d.util.Future;
35import com.android.gallery3d.util.FutureListener;
36import com.android.gallery3d.util.ThreadPool;
37
38public class SinglePhotoDataAdapter extends TileImageViewAdapter
39        implements PhotoPage.Model {
40
41    private static final String TAG = "SinglePhotoDataAdapter";
42    private static final int SIZE_BACKUP = 1024;
43    private static final int MSG_UPDATE_IMAGE = 1;
44
45    private MediaItem mItem;
46    private boolean mHasFullImage;
47    private Future<?> mTask;
48    private Handler mHandler;
49
50    private PhotoView mPhotoView;
51    private ThreadPool mThreadPool;
52
53    public SinglePhotoDataAdapter(
54            GalleryActivity activity, PhotoView view, MediaItem item) {
55        mItem = Utils.checkNotNull(item);
56        mHasFullImage = (item.getSupportedOperations() &
57                MediaItem.SUPPORT_FULL_IMAGE) != 0;
58        mPhotoView = Utils.checkNotNull(view);
59        mHandler = new SynchronizedHandler(activity.getGLRoot()) {
60            @Override
61            @SuppressWarnings("unchecked")
62            public void handleMessage(Message message) {
63                Utils.assertTrue(message.what == MSG_UPDATE_IMAGE);
64                if (mHasFullImage) {
65                    onDecodeLargeComplete((ImageBundle) message.obj);
66                } else {
67                    onDecodeThumbComplete((Future<Bitmap>) message.obj);
68                }
69            }
70        };
71        mThreadPool = activity.getThreadPool();
72    }
73
74    private static class ImageBundle {
75        public final BitmapRegionDecoder decoder;
76        public final Bitmap backupImage;
77
78        public ImageBundle(BitmapRegionDecoder decoder, Bitmap backupImage) {
79            this.decoder = decoder;
80            this.backupImage = backupImage;
81        }
82    }
83
84    private FutureListener<BitmapRegionDecoder> mLargeListener =
85            new FutureListener<BitmapRegionDecoder>() {
86        public void onFutureDone(Future<BitmapRegionDecoder> future) {
87            BitmapRegionDecoder decoder = future.get();
88            if (decoder == null) return;
89            int width = decoder.getWidth();
90            int height = decoder.getHeight();
91            BitmapFactory.Options options = new BitmapFactory.Options();
92            options.inSampleSize = BitmapUtils.computeSampleSize(
93                    (float) SIZE_BACKUP / Math.max(width, height));
94            Bitmap bitmap = decoder.decodeRegion(new Rect(0, 0, width, height), options);
95            mHandler.sendMessage(mHandler.obtainMessage(
96                    MSG_UPDATE_IMAGE, new ImageBundle(decoder, bitmap)));
97        }
98    };
99
100    private FutureListener<Bitmap> mThumbListener =
101            new FutureListener<Bitmap>() {
102        public void onFutureDone(Future<Bitmap> future) {
103            mHandler.sendMessage(
104                    mHandler.obtainMessage(MSG_UPDATE_IMAGE, future));
105        }
106    };
107
108    public boolean isEmpty() {
109        return false;
110    }
111
112    private void onDecodeLargeComplete(ImageBundle bundle) {
113        try {
114            setScreenNail(bundle.backupImage,
115                    bundle.decoder.getWidth(), bundle.decoder.getHeight());
116            setRegionDecoder(bundle.decoder);
117            mPhotoView.notifyImageChange(0);
118        } catch (Throwable t) {
119            Log.w(TAG, "fail to decode large", t);
120        }
121    }
122
123    private void onDecodeThumbComplete(Future<Bitmap> future) {
124        try {
125            Bitmap backup = future.get();
126            if (backup == null) return;
127            setScreenNail(backup, backup.getWidth(), backup.getHeight());
128            mPhotoView.notifyImageChange(0);
129        } catch (Throwable t) {
130            Log.w(TAG, "fail to decode thumb", t);
131        }
132    }
133
134    public void resume() {
135        if (mTask == null) {
136            if (mHasFullImage) {
137                mTask = mThreadPool.submit(
138                        mItem.requestLargeImage(), mLargeListener);
139            } else {
140                mTask = mThreadPool.submit(
141                        mItem.requestImage(MediaItem.TYPE_THUMBNAIL),
142                        mThumbListener);
143            }
144        }
145    }
146
147    public void pause() {
148        Future<?> task = mTask;
149        task.cancel();
150        task.waitDone();
151        if (task.get() == null) {
152            mTask = null;
153        }
154    }
155
156    @Override
157    public void moveTo(int index) {
158        throw new UnsupportedOperationException();
159    }
160
161    @Override
162    public void getImageSize(int offset, PhotoView.Size size) {
163        if (offset == 0) {
164            size.width = mItem.getWidth();
165            size.height = mItem.getHeight();
166        } else {
167            size.width = 0;
168            size.height = 0;
169        }
170    }
171
172    @Override
173    public int getImageRotation(int offset) {
174        return (offset == 0) ? mItem.getFullImageRotation() : 0;
175    }
176
177    @Override
178    public ScreenNail getScreenNail(int offset) {
179        return (offset == 0) ? getScreenNail() : null;
180    }
181
182    @Override
183    public void setNeedFullImage(boolean enabled) {
184        // currently not necessary.
185    }
186
187    @Override
188    public boolean isCamera(int offset) {
189        return false;
190    }
191
192    @Override
193    public boolean isVideo(int offset) {
194        return mItem.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO;
195    }
196
197    public MediaItem getCurrentMediaItem() {
198        return mItem;
199    }
200
201    public int getCurrentIndex() {
202        return 0;
203    }
204
205    public void setCurrentPhoto(Path path, int indexHint) {
206        // ignore
207    }
208}
209