blob: ea14117001942d2c12c382a39104054f5b638f3f [file] [log] [blame]
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001/*
2 * Copyright (C) 2007 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.camera;
18
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080019import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.content.SharedPreferences;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080023import android.graphics.Bitmap;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080024import android.net.Uri;
25import android.os.Bundle;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080026import android.preference.PreferenceManager;
27import android.provider.MediaStore;
28import android.util.AttributeSet;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080029import android.util.Log;
30import android.view.GestureDetector;
31import android.view.KeyEvent;
32import android.view.Menu;
33import android.view.MenuItem;
34import android.view.MotionEvent;
35import android.view.View;
36import android.view.Window;
37import android.view.WindowManager;
Owen Lin71ea3a32009-07-30 10:23:30 +080038import android.view.View.OnTouchListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080039import android.view.animation.AlphaAnimation;
40import android.view.animation.Animation;
41import android.view.animation.AnimationUtils;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080042import android.widget.Toast;
43import android.widget.ZoomButtonsController;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080044
Owen Lin8b3ecb22009-09-02 16:25:08 +080045import com.android.camera.gallery.IImage;
46import com.android.camera.gallery.IImageList;
47import com.android.camera.gallery.VideoObject;
48
Chih-Chung Chang063f09d2009-04-01 04:02:00 -070049import java.util.Random;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080050
Chih-Chung Chang73b7a3a2009-04-12 23:28:16 -070051// This activity can display a whole picture and navigate them in a specific
52// gallery. It has two modes: normal mode and slide show mode. In normal mode
53// the user view one image at a time, and can click "previous" and "next"
54// button to see the previous or next image. In slide show mode it shows one
55// image after another, with some transition effect.
Chih-Chung Chang063f09d2009-04-01 04:02:00 -070056public class ViewImage extends Activity implements View.OnClickListener {
Owen Line2950602009-05-22 01:50:27 -070057 private static final String PREF_SLIDESHOW_REPEAT =
58 "pref_gallery_slideshow_repeat_key";
59 private static final String PREF_SHUFFLE_SLIDESHOW =
60 "pref_gallery_slideshow_shuffle_key";
61 private static final String STATE_URI = "uri";
62 private static final String STATE_SLIDESHOW = "slideshow";
63 private static final String EXTRA_SLIDESHOW = "slideshow";
The Android Open Source Projectde365d82009-03-18 17:39:48 -070064 private static final String TAG = "ViewImage";
The Android Open Source Projectde365d82009-03-18 17:39:48 -070065
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080066 private ImageGetter mGetter;
Ray Chen72e1dfd2009-03-24 21:13:16 -070067 private Uri mSavedUri;
Chih-Chung Chang6a1abe12009-09-24 21:17:51 -070068 boolean mPaused = true;
Owen Lin69bd2712009-08-06 15:29:34 +080069 private boolean mShowControls = true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080070
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080071 // Choices for what adjacents to load.
Owen Line2950602009-05-22 01:50:27 -070072 private static final int[] sOrderAdjacents = new int[] {0, 1, -1};
73 private static final int[] sOrderSlideshow = new int[] {0};
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080074
Chih-Chung Chang4250e212009-07-24 10:58:40 +080075 final GetterHandler mHandler = new GetterHandler();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080076
Owen Lin41a85782009-04-20 15:59:57 +080077 private final Random mRandom = new Random(System.currentTimeMillis());
Owen Line2950602009-05-22 01:50:27 -070078 private int [] mShuffleOrder = null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080079 private boolean mUseShuffleOrder = false;
80 private boolean mSlideShowLoop = false;
81
Chih-Chung Chang3321d402009-04-02 21:45:14 -070082 static final int MODE_NORMAL = 1;
83 static final int MODE_SLIDESHOW = 2;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080084 private int mMode = MODE_NORMAL;
Owen Line2950602009-05-22 01:50:27 -070085
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080086 private boolean mFullScreenInNormalMode;
87 private boolean mShowActionIcons;
88 private View mActionIconPanel;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080089
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080090 private int mSlideShowInterval;
91 private int mLastSlideShowImage;
Chih-Chung Chang3321d402009-04-02 21:45:14 -070092 int mCurrentPosition = 0;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080093
94 // represents which style animation to use
95 private int mAnimationIndex;
96 private Animation [] mSlideShowInAnimation;
97 private Animation [] mSlideShowOutAnimation;
98
99 private SharedPreferences mPrefs;
100
Owen Line2950602009-05-22 01:50:27 -0700101 private View mNextImageView;
102 private View mPrevImageView;
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800103 private final Animation mHideNextImageViewAnimation =
104 new AlphaAnimation(1F, 0F);
105 private final Animation mHidePrevImageViewAnimation =
106 new AlphaAnimation(1F, 0F);
107 private final Animation mShowNextImageViewAnimation =
108 new AlphaAnimation(0F, 1F);
109 private final Animation mShowPrevImageViewAnimation =
110 new AlphaAnimation(0F, 1F);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800111
Owen Linf2718932009-06-03 17:07:33 -0700112 public static final String KEY_IMAGE_LIST = "image_list";
Owen Lin69bd2712009-08-06 15:29:34 +0800113 private static final String STATE_SHOW_CONTROLS = "show_controls";
Owen Linf2718932009-06-03 17:07:33 -0700114
Owen Lin101d5282009-04-03 16:20:08 -0700115 IImageList mAllImages;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800116
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800117 private ImageManager.ImageListParam mParam;
Owen Linb0e12822009-06-22 15:53:26 -0700118
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800119 private int mSlideShowImageCurrent = 0;
Owen Lin41a85782009-04-20 15:59:57 +0800120 private final ImageViewTouchBase [] mSlideShowImageViews =
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700121 new ImageViewTouchBase[2];
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800122
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700123 GestureDetector mGestureDetector;
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700124 private ZoomButtonsController mZoomButtonsController;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800125
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700126 // The image view displayed for normal mode.
127 private ImageViewTouch mImageView;
128 // This is the cache for thumbnail bitmaps.
129 private BitmapCache mCache;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800130 private MenuHelper.MenuItemsResult mImageMenuRunnable;
Owen Lin71ea3a32009-07-30 10:23:30 +0800131 private final Runnable mDismissOnScreenControlRunner = new Runnable() {
132 public void run() {
133 hideOnScreenControls();
134 }
135 };
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800136
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800137 private void updateNextPrevControls() {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700138 boolean showPrev = mCurrentPosition > 0;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800139 boolean showNext = mCurrentPosition < mAllImages.getCount() - 1;
140
141 boolean prevIsVisible = mPrevImageView.getVisibility() == View.VISIBLE;
142 boolean nextIsVisible = mNextImageView.getVisibility() == View.VISIBLE;
143
144 if (showPrev && !prevIsVisible) {
145 Animation a = mShowPrevImageViewAnimation;
146 a.setDuration(500);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700147 mPrevImageView.startAnimation(a);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800148 mPrevImageView.setVisibility(View.VISIBLE);
149 } else if (!showPrev && prevIsVisible) {
150 Animation a = mHidePrevImageViewAnimation;
151 a.setDuration(500);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700152 mPrevImageView.startAnimation(a);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800153 mPrevImageView.setVisibility(View.GONE);
154 }
155
156 if (showNext && !nextIsVisible) {
157 Animation a = mShowNextImageViewAnimation;
158 a.setDuration(500);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700159 mNextImageView.startAnimation(a);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800160 mNextImageView.setVisibility(View.VISIBLE);
161 } else if (!showNext && nextIsVisible) {
162 Animation a = mHideNextImageViewAnimation;
163 a.setDuration(500);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700164 mNextImageView.startAnimation(a);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800165 mNextImageView.setVisibility(View.GONE);
166 }
167 }
168
Owen Lin71ea3a32009-07-30 10:23:30 +0800169 private void hideOnScreenControls() {
170 if (mShowActionIcons
171 && mActionIconPanel.getVisibility() == View.VISIBLE) {
172 Animation animation = new AlphaAnimation(1, 0);
173 animation.setDuration(500);
174 mActionIconPanel.startAnimation(animation);
175 mActionIconPanel.setVisibility(View.INVISIBLE);
176 }
177
178 if (mNextImageView.getVisibility() == View.VISIBLE) {
179 Animation a = mHideNextImageViewAnimation;
180 a.setDuration(500);
181 mNextImageView.startAnimation(a);
182 mNextImageView.setVisibility(View.INVISIBLE);
183 }
184
185 if (mPrevImageView.getVisibility() == View.VISIBLE) {
186 Animation a = mHidePrevImageViewAnimation;
187 a.setDuration(500);
188 mPrevImageView.startAnimation(a);
189 mPrevImageView.setVisibility(View.INVISIBLE);
190 }
191
192 mZoomButtonsController.setVisible(false);
193 }
194
195 private void showOnScreenControls() {
Owen Lin145b61a2009-06-25 11:12:11 -0700196 if (mPaused) return;
Owen Line2950602009-05-22 01:50:27 -0700197 // If the view has not been attached to the window yet, the
198 // zoomButtonControls will not able to show up. So delay it until the
199 // view has attached to window.
200 if (mActionIconPanel.getWindowToken() == null) {
201 mHandler.postGetterCallback(new Runnable() {
202 public void run() {
Owen Lin71ea3a32009-07-30 10:23:30 +0800203 showOnScreenControls();
Owen Line2950602009-05-22 01:50:27 -0700204 }
205 });
206 return;
207 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800208 updateNextPrevControls();
Owen Line2950602009-05-22 01:50:27 -0700209
Owen Lin317fe842009-06-05 18:28:07 -0700210 IImage image = mAllImages.getImageAt(mCurrentPosition);
211 if (image instanceof VideoObject) {
212 mZoomButtonsController.setVisible(false);
213 } else {
214 updateZoomButtonsEnabled();
215 mZoomButtonsController.setVisible(true);
216 }
Owen Linf0abe582009-06-08 17:26:52 -0700217
Owen Line2950602009-05-22 01:50:27 -0700218 if (mShowActionIcons
219 && mActionIconPanel.getVisibility() != View.VISIBLE) {
220 Animation animation = new AlphaAnimation(0, 1);
221 animation.setDuration(500);
222 mActionIconPanel.startAnimation(animation);
223 mActionIconPanel.setVisibility(View.VISIBLE);
224 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800225 }
226
227 @Override
228 public boolean dispatchTouchEvent(MotionEvent m) {
Chih-Chung Changd06aa692009-07-23 10:06:33 +0800229 if (mPaused) return true;
Owen Lin8b3ecb22009-09-02 16:25:08 +0800230 if (mZoomButtonsController.isVisible()) {
Owen Lin71ea3a32009-07-30 10:23:30 +0800231 scheduleDismissOnScreenControls();
Owen Lin31817e92009-03-27 16:30:02 -0700232 }
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800233 return super.dispatchTouchEvent(m);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800234 }
235
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700236 private void updateZoomButtonsEnabled() {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700237 ImageViewTouch imageView = mImageView;
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700238 float scale = imageView.getScale();
239 mZoomButtonsController.setZoomInEnabled(scale < imageView.mMaxZoom);
240 mZoomButtonsController.setZoomOutEnabled(scale > 1);
241 }
242
Andreas Huber5ae65322009-03-24 18:39:29 -0700243 @Override
244 protected void onDestroy() {
245 // This is necessary to make the ZoomButtonsController unregister
246 // its configuration change receiver.
247 if (mZoomButtonsController != null) {
248 mZoomButtonsController.setVisible(false);
249 }
Andreas Huber5ae65322009-03-24 18:39:29 -0700250 super.onDestroy();
251 }
252
Owen Lin71ea3a32009-07-30 10:23:30 +0800253 private void scheduleDismissOnScreenControls() {
254 mHandler.removeCallbacks(mDismissOnScreenControlRunner);
255 mHandler.postDelayed(mDismissOnScreenControlRunner, 2000);
256 }
257
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800258 private void setupOnScreenControls(View rootView, View ownerView) {
259 mNextImageView = rootView.findViewById(R.id.next_image);
260 mPrevImageView = rootView.findViewById(R.id.prev_image);
Owen Lin71ea3a32009-07-30 10:23:30 +0800261
262 mNextImageView.setOnClickListener(this);
263 mPrevImageView.setOnClickListener(this);
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800264
265 setupZoomButtonController(ownerView);
266 setupOnTouchListeners(rootView);
Owen Lin71ea3a32009-07-30 10:23:30 +0800267 }
268
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800269 private void setupZoomButtonController(final View ownerView) {
270 mZoomButtonsController = new ZoomButtonsController(ownerView);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700271 mZoomButtonsController.setAutoDismissed(false);
Wu-cheng Li559899a2009-06-30 15:26:48 +0800272 mZoomButtonsController.setZoomSpeed(100);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700273 mZoomButtonsController.setOnZoomListener(
274 new ZoomButtonsController.OnZoomListener() {
275 public void onVisibilityChanged(boolean visible) {
276 if (visible) {
277 updateZoomButtonsEnabled();
278 }
279 }
280
281 public void onZoom(boolean zoomIn) {
282 if (zoomIn) {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700283 mImageView.zoomIn();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700284 } else {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700285 mImageView.zoomOut();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700286 }
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800287 mZoomButtonsController.setVisible(true);
Owen Lin61dda552009-05-12 18:14:56 -0700288 updateZoomButtonsEnabled();
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700289 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700290 });
291 }
292
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800293 private void setupOnTouchListeners(View rootView) {
294 mGestureDetector = new GestureDetector(this, new MyGestureListener());
295
296 // If the user touches anywhere on the panel (including the
297 // next/prev button). We show the on-screen controls. In addition
298 // to that, if the touch is not on the prev/next button, we
299 // pass the event to the gesture detector to detect double tap.
300 final OnTouchListener buttonListener = new OnTouchListener() {
301 public boolean onTouch(View v, MotionEvent event) {
302 scheduleDismissOnScreenControls();
303 return false;
304 }
305 };
306
307 OnTouchListener rootListener = new OnTouchListener() {
308 public boolean onTouch(View v, MotionEvent event) {
309 buttonListener.onTouch(v, event);
310 mGestureDetector.onTouchEvent(event);
311
312 // We do not use the return value of
313 // mGestureDetector.onTouchEvent because we will not receive
314 // the "up" event if we return false for the "down" event.
315 return true;
316 }
317 };
318
319 mNextImageView.setOnTouchListener(buttonListener);
320 mPrevImageView.setOnTouchListener(buttonListener);
321 rootView.setOnTouchListener(rootListener);
322 }
323
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700324 private class MyGestureListener extends
325 GestureDetector.SimpleOnGestureListener {
326
327 @Override
328 public boolean onScroll(MotionEvent e1, MotionEvent e2,
329 float distanceX, float distanceY) {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700330 ImageViewTouch imageView = mImageView;
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700331 if (imageView.getScale() > 1F) {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700332 imageView.postTranslateCenter(-distanceX, -distanceY);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700333 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700334 return true;
335 }
336
337 @Override
338 public boolean onSingleTapUp(MotionEvent e) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700339 setMode(MODE_NORMAL);
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700340 return true;
341 }
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800342
343 @Override
344 public boolean onSingleTapConfirmed(MotionEvent e) {
345 showOnScreenControls();
346 scheduleDismissOnScreenControls();
347 return true;
348 }
349
350 @Override
351 public boolean onDoubleTap(MotionEvent e) {
352 ImageViewTouch imageView = mImageView;
353
354 // Switch between the original scale and 3x scale.
355 if (imageView.getScale() > 2F) {
356 mImageView.zoomTo(1f);
357 } else {
358 mImageView.zoomToPoint(3f, e.getX(), e.getY());
359 }
360 return true;
361 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700362 }
363
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700364 boolean isPickIntent() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800365 String action = getIntent().getAction();
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700366 return (Intent.ACTION_PICK.equals(action)
367 || Intent.ACTION_GET_CONTENT.equals(action));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800368 }
369
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800370 @Override
Owen Lin9b2e9122009-03-27 15:10:14 -0700371 public boolean onCreateOptionsMenu(Menu menu) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800372 super.onCreateOptionsMenu(menu);
373
Chih-Chung Changd1890832009-09-08 13:32:52 +0800374 MenuItem item = menu.add(Menu.NONE, Menu.NONE,
375 MenuHelper.POSITION_SLIDESHOW,
376 R.string.slide_show);
Owen Lin6149fad2009-06-25 14:58:54 -0700377 item.setOnMenuItemClickListener(
378 new MenuItem.OnMenuItemClickListener() {
379 public boolean onMenuItemClick(MenuItem item) {
380 setMode(MODE_SLIDESHOW);
381 mLastSlideShowImage = mCurrentPosition;
382 loadNextImage(mCurrentPosition, 0, true);
383 return true;
384 }
385 });
386 item.setIcon(android.R.drawable.ic_menu_slideshow);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800387
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800388 mImageMenuRunnable = MenuHelper.addImageMenuItems(
389 menu,
390 MenuHelper.INCLUDE_ALL,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800391 ViewImage.this,
Ray Chen993105a2009-04-10 02:11:35 -0700392 mHandler,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800393 mDeletePhotoRunnable,
394 new MenuHelper.MenuInvoker() {
Ray Chen993105a2009-04-10 02:11:35 -0700395 public void run(final MenuHelper.MenuCallback cb) {
Chih-Chung Chang06f43ba2009-07-02 17:07:20 +0800396 if (mPaused) return;
397 setMode(MODE_NORMAL);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800398
Chih-Chung Chang06f43ba2009-07-02 17:07:20 +0800399 IImage image = mAllImages.getImageAt(mCurrentPosition);
400 Uri uri = image.fullSizeImageUri();
401 cb.run(uri, image);
Chih-Chung Chang35f8af02009-07-01 14:52:24 +0800402
Chih-Chung Chang06f43ba2009-07-02 17:07:20 +0800403 mImageView.clear();
Owen Lin69bd2712009-08-06 15:29:34 +0800404 setImage(mCurrentPosition, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800405 }
406 });
407
Chih-Chung Changd1890832009-09-08 13:32:52 +0800408 item = menu.add(Menu.NONE, Menu.NONE,
409 MenuHelper.POSITION_GALLERY_SETTING, R.string.camerasettings);
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800410 item.setOnMenuItemClickListener(
411 new MenuItem.OnMenuItemClickListener() {
412 public boolean onMenuItemClick(MenuItem item) {
413 Intent preferences = new Intent();
414 preferences.setClass(ViewImage.this, GallerySettings.class);
415 startActivity(preferences);
416 return true;
417 }
418 });
419 item.setAlphabeticShortcut('p');
420 item.setIcon(android.R.drawable.ic_menu_preferences);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800421
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800422 return true;
423 }
424
425 protected Runnable mDeletePhotoRunnable = new Runnable() {
426 public void run() {
427 mAllImages.removeImageAt(mCurrentPosition);
428 if (mAllImages.getCount() == 0) {
429 finish();
Owen Lin71ea3a32009-07-30 10:23:30 +0800430 return;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800431 } else {
432 if (mCurrentPosition == mAllImages.getCount()) {
433 mCurrentPosition -= 1;
434 }
435 }
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700436 mImageView.clear();
437 mCache.clear(); // Because the position number is changed.
Owen Lin69bd2712009-08-06 15:29:34 +0800438 setImage(mCurrentPosition, true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800439 }
440 };
441
442 @Override
Owen Lin9b2e9122009-03-27 15:10:14 -0700443 public boolean onPrepareOptionsMenu(Menu menu) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800444
Owen Linb0e12822009-06-22 15:53:26 -0700445 super.onPrepareOptionsMenu(menu);
446 if (mPaused) return false;
447
448 setMode(MODE_NORMAL);
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800449 IImage image = mAllImages.getImageAt(mCurrentPosition);
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800450
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800451 if (mImageMenuRunnable != null) {
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800452 mImageMenuRunnable.gettingReadyToOpen(menu, image);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800453 }
454
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700455 Uri uri = mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri();
Chih-Chung Changb2a97652009-07-10 18:39:49 +0800456 MenuHelper.enableShareMenuItem(menu, MenuHelper.isWhiteListUri(uri));
Chih-Chung Changeb9d8a22009-03-27 16:07:25 -0700457
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800458 MenuHelper.enableShowOnMapMenuItem(menu, MenuHelper.hasLatLngData(image));
459
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800460 return true;
461 }
462
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800463 @Override
464 public boolean onMenuItemSelected(int featureId, MenuItem item) {
465 boolean b = super.onMenuItemSelected(featureId, item);
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700466 if (mImageMenuRunnable != null) {
467 mImageMenuRunnable.aboutToCall(item,
468 mAllImages.getImageAt(mCurrentPosition));
469 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800470 return b;
471 }
472
Owen Lin69bd2712009-08-06 15:29:34 +0800473 void setImage(int pos, boolean showControls) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800474 mCurrentPosition = pos;
475
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700476 Bitmap b = mCache.getBitmap(pos);
477 if (b != null) {
Ray Chen012d0f32009-07-20 16:33:41 +0800478 IImage image = mAllImages.getImageAt(pos);
479 mImageView.setImageRotateBitmapResetBase(
480 new RotateBitmap(b, image.getDegreesRotated()), true);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700481 updateZoomButtonsEnabled();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800482 }
Owen Lin937fc482009-04-14 02:02:51 -0700483
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800484 ImageGetterCallback cb = new ImageGetterCallback() {
Chih-Chung Chang4250e212009-07-24 10:58:40 +0800485 public void completed() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800486 }
487
488 public boolean wantsThumbnail(int pos, int offset) {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700489 return !mCache.hasBitmap(pos + offset);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800490 }
491
492 public boolean wantsFullImage(int pos, int offset) {
Owen Line2950602009-05-22 01:50:27 -0700493 return offset == 0;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800494 }
495
496 public int fullImageSizeToUse(int pos, int offset) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700497 // this number should be bigger so that we can zoom. we may
498 // need to get fancier and read in the fuller size image as the
Wei-Ta Chend5d74642009-06-11 16:13:13 +0800499 // user starts to zoom.
500 // Originally the value is set to 480 in order to avoid OOM.
Wei-Ta Chenf2c7e982009-07-29 17:24:50 +0800501 // Now we set it to 2048 because of using
502 // native memory allocation for Bitmaps.
Wei-Ta Chend5d74642009-06-11 16:13:13 +0800503 final int imageViewSize = 2048;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800504 return imageViewSize;
505 }
506
507 public int [] loadOrder() {
Owen Line2950602009-05-22 01:50:27 -0700508 return sOrderAdjacents;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800509 }
510
Ray Chen012d0f32009-07-20 16:33:41 +0800511 public void imageLoaded(int pos, int offset, RotateBitmap bitmap,
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700512 boolean isThumb) {
Owen Lin3102f062009-03-24 20:38:25 -0700513 // shouldn't get here after onPause()
Chih-Chung Chang3b63aaa2009-05-25 11:16:48 +0800514
515 // We may get a result from a previous request. Ignore it.
516 if (pos != mCurrentPosition) {
517 bitmap.recycle();
518 return;
519 }
520
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700521 if (isThumb) {
Ray Chen012d0f32009-07-20 16:33:41 +0800522 mCache.put(pos + offset, bitmap.getBitmap());
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700523 }
Ray Chen993105a2009-04-10 02:11:35 -0700524 if (offset == 0) {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700525 // isThumb: We always load thumb bitmap first, so we will
526 // reset the supp matrix for then thumb bitmap, and keep
527 // the supp matrix when the full bitmap is loaded.
Ray Chen012d0f32009-07-20 16:33:41 +0800528 mImageView.setImageRotateBitmapResetBase(bitmap, isThumb);
Ray Chen993105a2009-04-10 02:11:35 -0700529 updateZoomButtonsEnabled();
530 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800531 }
532 };
533
534 // Could be null if we're stopping a slide show in the course of pausing
535 if (mGetter != null) {
Chih-Chung Chang4250e212009-07-24 10:58:40 +0800536 mGetter.setPosition(pos, cb, mAllImages, mHandler);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800537 }
Owen Lin317fe842009-06-05 18:28:07 -0700538 updateActionIcons();
Owen Lin69bd2712009-08-06 15:29:34 +0800539 if (showControls) showOnScreenControls();
Owen Lin71ea3a32009-07-30 10:23:30 +0800540 scheduleDismissOnScreenControls();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800541 }
542
543 @Override
Owen Lin9b2e9122009-03-27 15:10:14 -0700544 public void onCreate(Bundle instanceState) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800545 super.onCreate(instanceState);
Owen Line2950602009-05-22 01:50:27 -0700546
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800547 Intent intent = getIntent();
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700548 mFullScreenInNormalMode = intent.getBooleanExtra(
549 MediaStore.EXTRA_FULL_SCREEN, true);
550 mShowActionIcons = intent.getBooleanExtra(
Owen Line2950602009-05-22 01:50:27 -0700551 MediaStore.EXTRA_SHOW_ACTION_ICONS, true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800552
553 mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800554
555 setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
556 requestWindowFeature(Window.FEATURE_NO_TITLE);
557 setContentView(R.layout.viewimage);
558
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700559 mImageView = (ImageViewTouch) findViewById(R.id.image);
Chih-Chung Chang1f463a62009-07-30 17:59:09 +0800560 mImageView.setEnableTrackballScroll(true);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700561 mCache = new BitmapCache(3);
562 mImageView.setRecycler(mCache);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800563
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800564 makeGetter();
565
566 mAnimationIndex = -1;
567
568 mSlideShowInAnimation = new Animation[] {
569 makeInAnimation(R.anim.transition_in),
570 makeInAnimation(R.anim.slide_in),
571 makeInAnimation(R.anim.slide_in_vertical),
572 };
573
574 mSlideShowOutAnimation = new Animation[] {
575 makeOutAnimation(R.anim.transition_out),
576 makeOutAnimation(R.anim.slide_out),
577 makeOutAnimation(R.anim.slide_out_vertical),
578 };
579
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700580 mSlideShowImageViews[0] =
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700581 (ImageViewTouchBase) findViewById(R.id.image1_slideShow);
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700582 mSlideShowImageViews[1] =
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700583 (ImageViewTouchBase) findViewById(R.id.image2_slideShow);
584 for (ImageViewTouchBase v : mSlideShowImageViews) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800585 v.setVisibility(View.INVISIBLE);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700586 v.setRecycler(mCache);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800587 }
588
589 mActionIconPanel = findViewById(R.id.action_icon_panel);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800590
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800591 mParam = getIntent().getParcelableExtra(KEY_IMAGE_LIST);
Owen Line2950602009-05-22 01:50:27 -0700592
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800593 boolean slideshow;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800594 if (instanceState != null) {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800595 mSavedUri = instanceState.getParcelable(STATE_URI);
Owen Line2950602009-05-22 01:50:27 -0700596 slideshow = instanceState.getBoolean(STATE_SLIDESHOW, false);
Owen Lin69bd2712009-08-06 15:29:34 +0800597 mShowControls = instanceState.getBoolean(STATE_SHOW_CONTROLS, true);
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800598 } else {
599 mSavedUri = getIntent().getData();
600 slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800601 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800602
Chih-Chung Changb2a97652009-07-10 18:39:49 +0800603 // We only show action icons for URIs that we know we can share and
604 // delete. Although we get read permission (for the images) from
605 // applications like MMS, we cannot pass the permission to other
606 // activities due to the current framework design.
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800607 if (!MenuHelper.isWhiteListUri(mSavedUri)) {
Owen Linf0abe582009-06-08 17:26:52 -0700608 mShowActionIcons = false;
609 }
610
Owen Line2950602009-05-22 01:50:27 -0700611 if (mShowActionIcons) {
612 int[] pickIds = {R.id.attach, R.id.cancel};
Owen Lin317fe842009-06-05 18:28:07 -0700613 int[] normalIds = {R.id.setas, R.id.play, R.id.share, R.id.discard};
Owen Lin6149fad2009-06-25 14:58:54 -0700614 int[] connectIds = isPickIntent() ? pickIds : normalIds;
Owen Line2950602009-05-22 01:50:27 -0700615 for (int id : connectIds) {
616 View view = mActionIconPanel.findViewById(id);
617 view.setVisibility(View.VISIBLE);
618 view.setOnClickListener(this);
619 }
620 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800621
Chih-Chung Chang10df8d22009-08-05 16:17:38 +0800622 // Don't show the "delete" icon for SingleImageList.
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800623 if (ImageManager.isSingleImageMode(mSavedUri.toString())) {
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800624 mActionIconPanel.findViewById(R.id.discard)
625 .setVisibility(View.GONE);
Chih-Chung Chang10df8d22009-08-05 16:17:38 +0800626 }
627
Owen Line2950602009-05-22 01:50:27 -0700628 if (slideshow) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800629 setMode(MODE_SLIDESHOW);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800630 } else {
631 if (mFullScreenInNormalMode) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700632 getWindow().addFlags(
633 WindowManager.LayoutParams.FLAG_FULLSCREEN);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800634 }
635 if (mShowActionIcons) {
636 mActionIconPanel.setVisibility(View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800637 }
638 }
639
Chih-Chung Changeb9b5372009-09-10 12:36:52 +0800640 setupOnScreenControls(findViewById(R.id.rootLayout), mImageView);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800641 }
642
Owen Lin317fe842009-06-05 18:28:07 -0700643 private void updateActionIcons() {
644 if (isPickIntent()) return;
645
646 IImage image = mAllImages.getImageAt(mCurrentPosition);
647 View panel = mActionIconPanel;
648 if (image instanceof VideoObject) {
649 panel.findViewById(R.id.setas).setVisibility(View.GONE);
650 panel.findViewById(R.id.play).setVisibility(View.VISIBLE);
651 } else {
652 panel.findViewById(R.id.setas).setVisibility(View.VISIBLE);
653 panel.findViewById(R.id.play).setVisibility(View.GONE);
654 }
655 }
656
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800657 private Animation makeInAnimation(int id) {
658 Animation inAnimation = AnimationUtils.loadAnimation(this, id);
659 return inAnimation;
660 }
661
662 private Animation makeOutAnimation(int id) {
663 Animation outAnimation = AnimationUtils.loadAnimation(this, id);
664 return outAnimation;
665 }
666
Owen Line2950602009-05-22 01:50:27 -0700667 private static int getPreferencesInteger(
668 SharedPreferences prefs, String key, int defaultValue) {
669 String value = prefs.getString(key, null);
670 try {
671 return value == null ? defaultValue : Integer.parseInt(value);
672 } catch (NumberFormatException ex) {
673 Log.e(TAG, "couldn't parse preference: " + value, ex);
674 return defaultValue;
675 }
676 }
677
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700678 void setMode(int mode) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800679 if (mMode == mode) {
680 return;
681 }
Owen Line2950602009-05-22 01:50:27 -0700682 View slideshowPanel = findViewById(R.id.slideShowContainer);
683 View normalPanel = findViewById(R.id.abs);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800684
685 Window win = getWindow();
686 mMode = mode;
687 if (mode == MODE_SLIDESHOW) {
Owen Line2950602009-05-22 01:50:27 -0700688 slideshowPanel.setVisibility(View.VISIBLE);
689 normalPanel.setVisibility(View.GONE);
690
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800691 win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
692 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Owen Line2950602009-05-22 01:50:27 -0700693
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700694 mImageView.clear();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800695 mActionIconPanel.setVisibility(View.GONE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800696
Owen Line2950602009-05-22 01:50:27 -0700697 slideshowPanel.getRootView().requestLayout();
Chih-Chung Chang2b82c4a2009-04-14 18:00:10 +0800698
699 // The preferences we want to read:
700 // mUseShuffleOrder
701 // mSlideShowLoop
702 // mAnimationIndex
703 // mSlideShowInterval
704
Owen Line2950602009-05-22 01:50:27 -0700705 mUseShuffleOrder = mPrefs.getBoolean(PREF_SHUFFLE_SLIDESHOW, false);
706 mSlideShowLoop = mPrefs.getBoolean(PREF_SLIDESHOW_REPEAT, false);
707 mAnimationIndex = getPreferencesInteger(
708 mPrefs, "pref_gallery_slideshow_transition_key", 0);
709 mSlideShowInterval = getPreferencesInteger(
710 mPrefs, "pref_gallery_slideshow_interval_key", 3) * 1000;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800711 } else {
Owen Line2950602009-05-22 01:50:27 -0700712 slideshowPanel.setVisibility(View.GONE);
713 normalPanel.setVisibility(View.VISIBLE);
714
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800715 win.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
716 if (mFullScreenInNormalMode) {
717 win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
718 } else {
719 win.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
720 }
721
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700722 if (mGetter != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800723 mGetter.cancelCurrent();
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700724 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800725
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800726 if (mShowActionIcons) {
Owen Line2950602009-05-22 01:50:27 -0700727 Animation animation = new AlphaAnimation(0F, 1F);
728 animation.setDuration(500);
729 mActionIconPanel.setAnimation(animation);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800730 mActionIconPanel.setVisibility(View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800731 }
732
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700733 ImageViewTouchBase dst = mImageView;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800734 dst.mLastXTouchPos = -1;
735 dst.mLastYTouchPos = -1;
736
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700737 for (ImageViewTouchBase ivt : mSlideShowImageViews) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800738 ivt.clear();
739 }
740
741 mShuffleOrder = null;
742
743 // mGetter null is a proxy for being paused
744 if (mGetter != null) {
Owen Lin69bd2712009-08-06 15:29:34 +0800745 setImage(mCurrentPosition, true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800746 }
747 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800748 }
749
750 private void generateShuffleOrder() {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700751 if (mShuffleOrder == null
752 || mShuffleOrder.length != mAllImages.getCount()) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800753 mShuffleOrder = new int[mAllImages.getCount()];
Owen Line2950602009-05-22 01:50:27 -0700754 for (int i = 0, n = mShuffleOrder.length; i < n; i++) {
755 mShuffleOrder[i] = i;
756 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800757 }
758
Owen Line2950602009-05-22 01:50:27 -0700759 for (int i = mShuffleOrder.length - 1; i >= 0; i--) {
760 int r = mRandom.nextInt(i + 1);
761 if (r != i) {
762 int tmp = mShuffleOrder[r];
763 mShuffleOrder[r] = mShuffleOrder[i];
764 mShuffleOrder[i] = tmp;
765 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800766 }
767 }
768
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700769 private void loadNextImage(final int requestedPos, final long delay,
770 final boolean firstCall) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800771 if (firstCall && mUseShuffleOrder) {
772 generateShuffleOrder();
773 }
774
775 final long targetDisplayTime = System.currentTimeMillis() + delay;
776
777 ImageGetterCallback cb = new ImageGetterCallback() {
Chih-Chung Chang4250e212009-07-24 10:58:40 +0800778 public void completed() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800779 }
780
781 public boolean wantsThumbnail(int pos, int offset) {
782 return true;
783 }
784
785 public boolean wantsFullImage(int pos, int offset) {
786 return false;
787 }
788
789 public int [] loadOrder() {
Owen Line2950602009-05-22 01:50:27 -0700790 return sOrderSlideshow;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800791 }
792
793 public int fullImageSizeToUse(int pos, int offset) {
794 return 480; // TODO compute this
795 }
796
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700797 public void imageLoaded(final int pos, final int offset,
Ray Chen012d0f32009-07-20 16:33:41 +0800798 final RotateBitmap bitmap, final boolean isThumb) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700799 long timeRemaining = Math.max(0,
800 targetDisplayTime - System.currentTimeMillis());
Owen Lin3102f062009-03-24 20:38:25 -0700801 mHandler.postDelayedGetterCallback(new Runnable() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800802 public void run() {
Ray Chen993105a2009-04-10 02:11:35 -0700803 if (mMode == MODE_NORMAL) {
804 return;
805 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800806
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700807 ImageViewTouchBase oldView =
808 mSlideShowImageViews[mSlideShowImageCurrent];
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800809
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700810 if (++mSlideShowImageCurrent
811 == mSlideShowImageViews.length) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800812 mSlideShowImageCurrent = 0;
813 }
814
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700815 ImageViewTouchBase newView =
816 mSlideShowImageViews[mSlideShowImageCurrent];
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800817 newView.setVisibility(View.VISIBLE);
Ray Chen012d0f32009-07-20 16:33:41 +0800818 newView.setImageRotateBitmapResetBase(bitmap, true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800819 newView.bringToFront();
820
821 int animation = 0;
822
823 if (mAnimationIndex == -1) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700824 int n = mRandom.nextInt(
825 mSlideShowInAnimation.length);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800826 animation = n;
827 } else {
828 animation = mAnimationIndex;
829 }
830
831 Animation aIn = mSlideShowInAnimation[animation];
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700832 newView.startAnimation(aIn);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800833 newView.setVisibility(View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800834
835 Animation aOut = mSlideShowOutAnimation[animation];
836 oldView.setVisibility(View.INVISIBLE);
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700837 oldView.startAnimation(aOut);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800838
839 mCurrentPosition = requestedPos;
840
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700841 if (mCurrentPosition == mLastSlideShowImage
842 && !firstCall) {
Owen Lin3102f062009-03-24 20:38:25 -0700843 if (mSlideShowLoop) {
844 if (mUseShuffleOrder) {
845 generateShuffleOrder();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800846 }
Owen Lin3102f062009-03-24 20:38:25 -0700847 } else {
848 setMode(MODE_NORMAL);
849 return;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800850 }
Owen Lin3102f062009-03-24 20:38:25 -0700851 }
852
Chih-Chung Chang3321d402009-04-02 21:45:14 -0700853 loadNextImage(
854 (mCurrentPosition + 1) % mAllImages.getCount(),
855 mSlideShowInterval, false);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800856 }
857 }, timeRemaining);
858 }
859 };
860 // Could be null if we're stopping a slide show in the course of pausing
861 if (mGetter != null) {
862 int pos = requestedPos;
863 if (mShuffleOrder != null) {
864 pos = mShuffleOrder[pos];
865 }
Chih-Chung Chang4250e212009-07-24 10:58:40 +0800866 mGetter.setPosition(pos, cb, mAllImages, mHandler);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800867 }
868 }
869
870 private void makeGetter() {
Ray Chenbde544f2009-09-30 14:33:15 -0700871 mGetter = new ImageGetter(getContentResolver());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800872 }
873
Owen Lin7c2eb952009-06-04 14:04:30 -0700874 private IImageList buildImageListFromUri(Uri uri) {
875 String sortOrder = mPrefs.getString(
876 "pref_gallery_sort_key", "descending");
Owen Lin6149fad2009-06-25 14:58:54 -0700877 int sort = sortOrder.equals("ascending")
Owen Lin7c2eb952009-06-04 14:04:30 -0700878 ? ImageManager.SORT_ASCENDING
879 : ImageManager.SORT_DESCENDING;
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800880 return ImageManager.makeImageList(getContentResolver(), uri, sort);
Owen Lin7c2eb952009-06-04 14:04:30 -0700881 }
882
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800883 private boolean init(Uri uri) {
Owen Linf2718932009-06-03 17:07:33 -0700884 if (uri == null) return false;
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800885 mAllImages = (mParam == null)
Owen Lin7c2eb952009-06-04 14:04:30 -0700886 ? buildImageListFromUri(uri)
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800887 : ImageManager.makeImageList(getContentResolver(), mParam);
Chih-Chung Changfd6da322009-05-04 16:49:30 +0800888 IImage image = mAllImages.getImageForUri(uri);
Owen Linf2718932009-06-03 17:07:33 -0700889 if (image == null) return false;
890 mCurrentPosition = mAllImages.getImageIndex(image);
891 mLastSlideShowImage = mCurrentPosition;
892 return true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800893 }
894
Ray Chen72e1dfd2009-03-24 21:13:16 -0700895 private Uri getCurrentUri() {
Owen Lin387833a2009-06-29 17:30:24 -0700896 if (mAllImages.getCount() == 0) return null;
Owen Lin101d5282009-04-03 16:20:08 -0700897 IImage image = mAllImages.getImageAt(mCurrentPosition);
Chih-Chung Chang5642d512009-10-09 15:07:17 +0800898 if (image == null) return null;
Owen Lin317fe842009-06-05 18:28:07 -0700899 return image.fullSizeImageUri();
Ray Chen72e1dfd2009-03-24 21:13:16 -0700900 }
Owen Lin9b2e9122009-03-27 15:10:14 -0700901
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800902 @Override
903 public void onSaveInstanceState(Bundle b) {
904 super.onSaveInstanceState(b);
Owen Line2950602009-05-22 01:50:27 -0700905 b.putParcelable(STATE_URI,
Owen Linf2718932009-06-03 17:07:33 -0700906 mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri());
Owen Line2950602009-05-22 01:50:27 -0700907 b.putBoolean(STATE_SLIDESHOW, mMode == MODE_SLIDESHOW);
Ray Chen35937472009-03-24 20:39:36 -0700908 }
Owen Lin9b2e9122009-03-27 15:10:14 -0700909
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800910 @Override
Owen Lin9e0bda22009-05-04 17:10:37 -0700911 public void onStart() {
912 super.onStart();
Owen Linb0e12822009-06-22 15:53:26 -0700913 mPaused = false;
Owen Lin937fc482009-04-14 02:02:51 -0700914
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800915 if (!init(mSavedUri)) {
Chih-Chung Changca1f8202009-09-14 12:46:16 +0800916 Log.w(TAG, "init failed: " + mSavedUri);
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800917 finish();
918 return;
919 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800920
921 // normally this will never be zero but if one "backs" into this
922 // activity after removing the sdcard it could be zero. in that
923 // case just "finish" since there's nothing useful that can happen.
Ray Chen72e1dfd2009-03-24 21:13:16 -0700924 int count = mAllImages.getCount();
925 if (count == 0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800926 finish();
Owen Lin71ea3a32009-07-30 10:23:30 +0800927 return;
Ray Chen72e1dfd2009-03-24 21:13:16 -0700928 } else if (count <= mCurrentPosition) {
929 mCurrentPosition = count - 1;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800930 }
931
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800932 if (mGetter == null) {
933 makeGetter();
934 }
935
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700936 if (mMode == MODE_SLIDESHOW) {
937 loadNextImage(mCurrentPosition, 0, true);
938 } else { // MODE_NORMAL
Owen Lin69bd2712009-08-06 15:29:34 +0800939 setImage(mCurrentPosition, mShowControls);
940 mShowControls = false;
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700941 }
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700942 }
943
944 @Override
Owen Lin9e0bda22009-05-04 17:10:37 -0700945 public void onStop() {
946 super.onStop();
Owen Linb0e12822009-06-22 15:53:26 -0700947 mPaused = true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800948
Chih-Chung Changca1f8202009-09-14 12:46:16 +0800949 // mGetter could be null if we call finish() and leave early in
950 // onStart().
951 if (mGetter != null) {
952 mGetter.cancelCurrent();
953 mGetter.stop();
954 mGetter = null;
955 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800956 setMode(MODE_NORMAL);
957
Owen Lin3102f062009-03-24 20:38:25 -0700958 // removing all callback in the message queue
959 mHandler.removeAllGetterCallbacks();
Owen Lin9b2e9122009-03-27 15:10:14 -0700960
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800961 if (mAllImages != null) {
962 mSavedUri = getCurrentUri();
963 mAllImages.close();
964 mAllImages = null;
965 }
Owen Linb0e12822009-06-22 15:53:26 -0700966
Owen Lin71ea3a32009-07-30 10:23:30 +0800967 hideOnScreenControls();
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700968 mImageView.clear();
969 mCache.clear();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800970
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -0700971 for (ImageViewTouchBase iv : mSlideShowImageViews) {
972 iv.clear();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800973 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800974 }
975
Owen Lin317fe842009-06-05 18:28:07 -0700976 private void startShareMediaActivity(IImage image) {
977 boolean isVideo = image instanceof VideoObject;
978 Intent intent = new Intent();
979 intent.setAction(Intent.ACTION_SEND);
980 intent.setType(image.getMimeType());
981 intent.putExtra(Intent.EXTRA_STREAM, image.fullSizeImageUri());
982 try {
983 startActivity(Intent.createChooser(intent, getText(
984 isVideo ? R.string.sendVideo : R.string.sendImage)));
985 } catch (android.content.ActivityNotFoundException ex) {
986 Toast.makeText(this, isVideo
987 ? R.string.no_way_to_share_image
988 : R.string.no_way_to_share_video,
989 Toast.LENGTH_SHORT).show();
990 }
991 }
992
993 private void startPlayVideoActivity() {
994 IImage image = mAllImages.getImageAt(mCurrentPosition);
995 Intent intent = new Intent(
996 Intent.ACTION_VIEW, image.fullSizeImageUri());
997 try {
998 startActivity(intent);
999 } catch (android.content.ActivityNotFoundException ex) {
1000 Log.e(TAG, "Couldn't view video " + image.fullSizeImageUri(), ex);
1001 }
1002 }
1003
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001004 public void onClick(View v) {
1005 switch (v.getId()) {
Owen Lin317fe842009-06-05 18:28:07 -07001006 case R.id.discard:
1007 MenuHelper.deletePhoto(this, mDeletePhotoRunnable);
1008 break;
1009 case R.id.play:
1010 startPlayVideoActivity();
1011 break;
1012 case R.id.share: {
1013 IImage image = mAllImages.getImageAt(mCurrentPosition);
Chih-Chung Changb2a97652009-07-10 18:39:49 +08001014 if (!MenuHelper.isWhiteListUri(image.fullSizeImageUri())) {
Owen Lin317fe842009-06-05 18:28:07 -07001015 return;
1016 }
1017 startShareMediaActivity(image);
1018 break;
Ray Chen993105a2009-04-10 02:11:35 -07001019 }
Owen Lin317fe842009-06-05 18:28:07 -07001020 case R.id.setas: {
Chih-Chung Changbb187782009-07-02 16:46:30 +08001021 IImage image = mAllImages.getImageAt(mCurrentPosition);
Wei-Ta Chend5d74642009-06-11 16:13:13 +08001022 Intent intent = Util.createSetAsIntent(image);
Owen Lin317fe842009-06-05 18:28:07 -07001023 try {
1024 startActivity(Intent.createChooser(
1025 intent, getText(R.string.setImage)));
1026 } catch (android.content.ActivityNotFoundException ex) {
1027 Toast.makeText(this, R.string.no_way_to_share_video,
1028 Toast.LENGTH_SHORT).show();
1029 }
1030 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001031 }
Owen Lin317fe842009-06-05 18:28:07 -07001032 case R.id.next_image:
1033 moveNextOrPrevious(1);
1034 break;
1035 case R.id.prev_image:
1036 moveNextOrPrevious(-1);
1037 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001038 }
1039 }
1040
1041 private void moveNextOrPrevious(int delta) {
1042 int nextImagePos = mCurrentPosition + delta;
1043 if ((0 <= nextImagePos) && (nextImagePos < mAllImages.getCount())) {
Owen Lin69bd2712009-08-06 15:29:34 +08001044 setImage(nextImagePos, true);
Owen Lin71ea3a32009-07-30 10:23:30 +08001045 showOnScreenControls();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001046 }
1047 }
1048
1049 @Override
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001050 protected void onActivityResult(int requestCode, int resultCode,
1051 Intent data) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001052 switch (requestCode) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001053 case MenuHelper.RESULT_COMMON_MENU_CROP:
1054 if (resultCode == RESULT_OK) {
1055 // The CropImage activity passes back the Uri of the
1056 // cropped image as the Action rather than the Data.
1057 mSavedUri = Uri.parse(data.getAction());
Owen Lin145b61a2009-06-25 11:12:11 -07001058
1059 // if onStart() runs before, then set the returned
1060 // image as currentImage.
1061 if (mAllImages != null) {
1062 IImage image = mAllImages.getImageForUri(mSavedUri);
Chih-Chung Changca1f8202009-09-14 12:46:16 +08001063 // image could be null if SD card is removed.
1064 if (image == null) {
1065 finish();
1066 } else {
1067 mCurrentPosition = mAllImages.getImageIndex(image);
1068 setImage(mCurrentPosition, false);
1069 }
Owen Lin145b61a2009-06-25 11:12:11 -07001070 }
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001071 }
1072 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001073 }
1074 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001075}
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001076
1077class ImageViewTouch extends ImageViewTouchBase {
Owen Lin41a85782009-04-20 15:59:57 +08001078 private final ViewImage mViewImage;
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001079 private boolean mEnableTrackballScroll;
1080
1081 public ImageViewTouch(Context context) {
1082 super(context);
1083 mViewImage = (ViewImage) context;
1084 }
1085
1086 public ImageViewTouch(Context context, AttributeSet attrs) {
1087 super(context, attrs);
1088 mViewImage = (ViewImage) context;
1089 }
1090
1091 public void setEnableTrackballScroll(boolean enable) {
1092 mEnableTrackballScroll = enable;
1093 }
1094
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001095 protected void postTranslateCenter(float dx, float dy) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001096 super.postTranslate(dx, dy);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001097 center(true, true);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001098 }
1099
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001100 private static final float PAN_RATE = 20;
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001101
Chih-Chung Chang1f463a62009-07-30 17:59:09 +08001102 // This is the time we allow the dpad to change the image position again.
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001103 private long mNextChangePositionTime;
Chih-Chung Chang1f463a62009-07-30 17:59:09 +08001104
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001105 @Override
1106 public boolean onKeyDown(int keyCode, KeyEvent event) {
Chih-Chung Chang6a1abe12009-09-24 21:17:51 -07001107 if (mViewImage.mPaused) return false;
1108
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001109 // Don't respond to arrow keys if trackball scrolling is not enabled
1110 if (!mEnableTrackballScroll) {
1111 if ((keyCode >= KeyEvent.KEYCODE_DPAD_UP)
1112 && (keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT)) {
1113 return super.onKeyDown(keyCode, event);
1114 }
1115 }
1116
1117 int current = mViewImage.mCurrentPosition;
1118
1119 int nextImagePos = -2; // default no next image
1120 try {
1121 switch (keyCode) {
1122 case KeyEvent.KEYCODE_DPAD_CENTER: {
1123 if (mViewImage.isPickIntent()) {
Owen Lin101d5282009-04-03 16:20:08 -07001124 IImage img = mViewImage.mAllImages
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001125 .getImageAt(mViewImage.mCurrentPosition);
1126 mViewImage.setResult(ViewImage.RESULT_OK,
1127 new Intent().setData(img.fullSizeImageUri()));
1128 mViewImage.finish();
1129 }
1130 break;
1131 }
1132 case KeyEvent.KEYCODE_DPAD_LEFT: {
Chih-Chung Chang1f463a62009-07-30 17:59:09 +08001133 if (getScale() <= 1F && event.getEventTime()
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001134 >= mNextChangePositionTime) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001135 nextImagePos = current - 1;
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001136 mNextChangePositionTime = event.getEventTime() + 500;
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001137 } else {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001138 panBy(PAN_RATE, 0);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001139 center(true, false);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001140 }
1141 return true;
1142 }
1143 case KeyEvent.KEYCODE_DPAD_RIGHT: {
Chih-Chung Chang1f463a62009-07-30 17:59:09 +08001144 if (getScale() <= 1F && event.getEventTime()
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001145 >= mNextChangePositionTime) {
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001146 nextImagePos = current + 1;
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001147 mNextChangePositionTime = event.getEventTime() + 500;
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001148 } else {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001149 panBy(-PAN_RATE, 0);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001150 center(true, false);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001151 }
1152 return true;
1153 }
1154 case KeyEvent.KEYCODE_DPAD_UP: {
1155 panBy(0, PAN_RATE);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001156 center(false, true);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001157 return true;
1158 }
1159 case KeyEvent.KEYCODE_DPAD_DOWN: {
1160 panBy(0, -PAN_RATE);
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001161 center(false, true);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001162 return true;
1163 }
1164 case KeyEvent.KEYCODE_DEL:
1165 MenuHelper.deletePhoto(
1166 mViewImage, mViewImage.mDeletePhotoRunnable);
1167 break;
1168 }
1169 } finally {
1170 if (nextImagePos >= 0
1171 && nextImagePos < mViewImage.mAllImages.getCount()) {
1172 synchronized (mViewImage) {
1173 mViewImage.setMode(ViewImage.MODE_NORMAL);
Owen Lin69bd2712009-08-06 15:29:34 +08001174 mViewImage.setImage(nextImagePos, true);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001175 }
1176 } else if (nextImagePos != -2) {
Chih-Chung Chang0a475e12009-04-16 11:42:12 +08001177 center(true, true);
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001178 }
1179 }
1180
1181 return super.onKeyDown(keyCode, event);
1182 }
Chih-Chung Chang3321d402009-04-02 21:45:14 -07001183}
1184
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001185// This is a cache for Bitmap displayed in ViewImage (normal mode, thumb only).
1186class BitmapCache implements ImageViewTouchBase.Recycler {
Chih-Chung Chang73b7a3a2009-04-12 23:28:16 -07001187 public static class Entry {
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001188 int mPos;
1189 Bitmap mBitmap;
1190 public Entry() {
1191 clear();
1192 }
1193 public void clear() {
1194 mPos = -1;
1195 mBitmap = null;
1196 }
1197 }
1198
Owen Lin41a85782009-04-20 15:59:57 +08001199 private final Entry[] mCache;
Owen Lin937fc482009-04-14 02:02:51 -07001200
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001201 public BitmapCache(int size) {
1202 mCache = new Entry[size];
1203 for (int i = 0; i < mCache.length; i++) {
1204 mCache[i] = new Entry();
1205 }
1206 }
1207
1208 // Given the position, find the associated entry. Returns null if there is
1209 // no such entry.
1210 private Entry findEntry(int pos) {
1211 for (Entry e : mCache) {
1212 if (pos == e.mPos) {
1213 return e;
1214 }
1215 }
1216 return null;
1217 }
Owen Lin937fc482009-04-14 02:02:51 -07001218
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001219 // Returns the thumb bitmap if we have it, otherwise return null.
1220 public synchronized Bitmap getBitmap(int pos) {
1221 Entry e = findEntry(pos);
1222 if (e != null) {
1223 return e.mBitmap;
1224 }
1225 return null;
1226 }
1227
1228 public synchronized void put(int pos, Bitmap bitmap) {
1229 // First see if we already have this entry.
1230 if (findEntry(pos) != null) {
1231 return;
1232 }
1233
1234 // Find the best entry we should replace.
1235 // See if there is any empty entry.
1236 // Otherwise assuming sequential access, kick out the entry with the
1237 // greatest distance.
1238 Entry best = null;
1239 int maxDist = -1;
1240 for (Entry e : mCache) {
1241 if (e.mPos == -1) {
1242 best = e;
1243 break;
1244 } else {
1245 int dist = Math.abs(pos - e.mPos);
1246 if (dist > maxDist) {
1247 maxDist = dist;
1248 best = e;
1249 }
1250 }
1251 }
Owen Lin937fc482009-04-14 02:02:51 -07001252
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001253 // Recycle the image being kicked out.
1254 // This only works because our current usage is sequential, so we
1255 // do not happen to recycle the image being displayed.
1256 if (best.mBitmap != null) {
1257 best.mBitmap.recycle();
1258 }
1259
1260 best.mPos = pos;
1261 best.mBitmap = bitmap;
1262 }
Owen Lin937fc482009-04-14 02:02:51 -07001263
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001264 // Recycle all bitmaps in the cache and clear the cache.
1265 public synchronized void clear() {
1266 for (Entry e : mCache) {
1267 if (e.mBitmap != null) {
1268 e.mBitmap.recycle();
1269 }
1270 e.clear();
1271 }
1272 }
1273
1274 // Returns whether the bitmap is in the cache.
1275 public synchronized boolean hasBitmap(int pos) {
1276 Entry e = findEntry(pos);
1277 return (e != null);
1278 }
Owen Lin937fc482009-04-14 02:02:51 -07001279
Chih-Chung Chang7db87ab2009-04-12 21:42:43 -07001280 // Recycle the bitmap if it's not in the cache.
1281 // The input must be non-null.
1282 public synchronized void recycle(Bitmap b) {
1283 for (Entry e : mCache) {
1284 if (e.mPos != -1) {
1285 if (e.mBitmap == b) {
1286 return;
1287 }
1288 }
1289 }
1290 b.recycle();
1291 }
1292}