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