1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.app;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.BitmapUtils;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.PhotoView;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.PhotoView.ImageData;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.SynchronizedHandler;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.TileImageViewAdapter;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener;
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool;
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapRegionDecoder;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Handler;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message;
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class SinglePhotoDataAdapter extends TileImageViewAdapter
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        implements PhotoPage.Model {
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "SinglePhotoDataAdapter";
425007a96dea76c9f3871b97579b51853029c115a0Owen Lin    private static final int SIZE_BACKUP = 1024;
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSG_UPDATE_IMAGE = 1;
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private MediaItem mItem;
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mHasFullImage;
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Future<?> mTask;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Handler mHandler;
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private PhotoView mPhotoView;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ThreadPool mThreadPool;
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public SinglePhotoDataAdapter(
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            GalleryActivity activity, PhotoView view, MediaItem item) {
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mItem = Utils.checkNotNull(item);
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHasFullImage = (item.getSupportedOperations() &
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                MediaItem.SUPPORT_FULL_IMAGE) != 0;
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mPhotoView = Utils.checkNotNull(view);
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHandler = new SynchronizedHandler(activity.getGLRoot()) {
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @Override
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @SuppressWarnings("unchecked")
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void handleMessage(Message message) {
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Utils.assertTrue(message.what == MSG_UPDATE_IMAGE);
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (mHasFullImage) {
655007a96dea76c9f3871b97579b51853029c115a0Owen Lin                    onDecodeLargeComplete((ImageBundle) message.obj);
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                } else {
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    onDecodeThumbComplete((Future<Bitmap>) message.obj);
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        };
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mThreadPool = activity.getThreadPool();
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
745007a96dea76c9f3871b97579b51853029c115a0Owen Lin    private static class ImageBundle {
755007a96dea76c9f3871b97579b51853029c115a0Owen Lin        public final BitmapRegionDecoder decoder;
765007a96dea76c9f3871b97579b51853029c115a0Owen Lin        public final Bitmap backupImage;
775007a96dea76c9f3871b97579b51853029c115a0Owen Lin
785007a96dea76c9f3871b97579b51853029c115a0Owen Lin        public ImageBundle(BitmapRegionDecoder decoder, Bitmap backupImage) {
795007a96dea76c9f3871b97579b51853029c115a0Owen Lin            this.decoder = decoder;
805007a96dea76c9f3871b97579b51853029c115a0Owen Lin            this.backupImage = backupImage;
815007a96dea76c9f3871b97579b51853029c115a0Owen Lin        }
825007a96dea76c9f3871b97579b51853029c115a0Owen Lin    }
835007a96dea76c9f3871b97579b51853029c115a0Owen Lin
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private FutureListener<BitmapRegionDecoder> mLargeListener =
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new FutureListener<BitmapRegionDecoder>() {
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onFutureDone(Future<BitmapRegionDecoder> future) {
875007a96dea76c9f3871b97579b51853029c115a0Owen Lin            BitmapRegionDecoder decoder = future.get();
885007a96dea76c9f3871b97579b51853029c115a0Owen Lin            if (decoder == null) return;
895007a96dea76c9f3871b97579b51853029c115a0Owen Lin            int width = decoder.getWidth();
905007a96dea76c9f3871b97579b51853029c115a0Owen Lin            int height = decoder.getHeight();
915007a96dea76c9f3871b97579b51853029c115a0Owen Lin            BitmapFactory.Options options = new BitmapFactory.Options();
925007a96dea76c9f3871b97579b51853029c115a0Owen Lin            options.inSampleSize = BitmapUtils.computeSampleSize(
935007a96dea76c9f3871b97579b51853029c115a0Owen Lin                    (float) SIZE_BACKUP / Math.max(width, height));
945007a96dea76c9f3871b97579b51853029c115a0Owen Lin            Bitmap bitmap = decoder.decodeRegion(new Rect(0, 0, width, height), options);
955007a96dea76c9f3871b97579b51853029c115a0Owen Lin            mHandler.sendMessage(mHandler.obtainMessage(
965007a96dea76c9f3871b97579b51853029c115a0Owen Lin                    MSG_UPDATE_IMAGE, new ImageBundle(decoder, bitmap)));
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    };
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private FutureListener<Bitmap> mThumbListener =
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new FutureListener<Bitmap>() {
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onFutureDone(Future<Bitmap> future) {
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mHandler.sendMessage(
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    mHandler.obtainMessage(MSG_UPDATE_IMAGE, future));
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    };
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean isEmpty() {
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return false;
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getImageRotation() {
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mItem.getRotation();
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1165007a96dea76c9f3871b97579b51853029c115a0Owen Lin    private void onDecodeLargeComplete(ImageBundle bundle) {
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
1185007a96dea76c9f3871b97579b51853029c115a0Owen Lin            setBackupImage(bundle.backupImage,
1195007a96dea76c9f3871b97579b51853029c115a0Owen Lin                    bundle.decoder.getWidth(), bundle.decoder.getHeight());
1205007a96dea76c9f3871b97579b51853029c115a0Owen Lin            setRegionDecoder(bundle.decoder);
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mPhotoView.notifyImageInvalidated(0);
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t) {
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, "fail to decode large", t);
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void onDecodeThumbComplete(Future<Bitmap> future) {
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
1295007a96dea76c9f3871b97579b51853029c115a0Owen Lin            Bitmap backup = future.get();
1305007a96dea76c9f3871b97579b51853029c115a0Owen Lin            if (backup == null) return;
1315007a96dea76c9f3871b97579b51853029c115a0Owen Lin            setBackupImage(backup, backup.getWidth(), backup.getHeight());
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mPhotoView.notifyOnNewImage();
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mPhotoView.notifyImageInvalidated(0); // the current image
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Throwable t) {
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, "fail to decode thumb", t);
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void resume() {
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mTask == null) {
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mHasFullImage) {
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mTask = mThreadPool.submit(
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        mItem.requestLargeImage(), mLargeListener);
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mTask = mThreadPool.submit(
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        mItem.requestImage(MediaItem.TYPE_THUMBNAIL),
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        mThumbListener);
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void pause() {
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Future<?> task = mTask;
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        task.cancel();
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        task.waitDone();
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (task.get() == null) {
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mTask = null;
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ImageData getNextImage() {
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return null;
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ImageData getPreviousImage() {
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return null;
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void next() {
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        throw new UnsupportedOperationException();
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void previous() {
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        throw new UnsupportedOperationException();
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1773a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang    public void jumpTo(int index) {
1783a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang        throw new UnsupportedOperationException();
1793a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang    }
1803a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public MediaItem getCurrentMediaItem() {
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mItem;
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getCurrentIndex() {
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return 0;
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setCurrentPhoto(Path path, int indexHint) {
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // ignore
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
193