blob: cfdc6347e64d92ecdfcecfca7c533e0332591596 [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;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080020import android.app.AlertDialog;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070021import android.app.Dialog;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080022import android.app.ProgressDialog;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080023import android.content.ActivityNotFoundException;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070024import android.content.BroadcastReceiver;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080025import android.content.Context;
26import android.content.DialogInterface;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.SharedPreferences;
30import android.content.pm.ActivityInfo;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070031import android.content.res.Configuration;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080032import android.graphics.Bitmap;
Owen Linb5d87cf2009-04-22 07:58:43 +080033import android.graphics.BitmapFactory;
34import android.graphics.Canvas;
35import android.graphics.Paint;
36import android.graphics.Rect;
37import android.graphics.drawable.Drawable;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080038import android.net.Uri;
39import android.os.Bundle;
40import android.os.Handler;
Owen Lin8f8cf382009-07-29 13:45:42 +080041import android.os.Parcelable;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070042import android.preference.PreferenceManager;
43import android.provider.MediaStore;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080044import android.util.Log;
45import android.view.ContextMenu;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080046import android.view.KeyEvent;
47import android.view.Menu;
48import android.view.MenuItem;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080049import android.view.View;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080050import android.view.Window;
Owen Lin601ce562009-04-29 17:47:19 -070051import android.view.View.OnClickListener;
Owen Lin228f1322009-04-23 16:24:26 -070052import android.view.animation.Animation;
53import android.view.animation.AnimationUtils;
Owen Lin601ce562009-04-29 17:47:19 -070054import android.widget.Button;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080055import android.widget.TextView;
Owen Lin8f8cf382009-07-29 13:45:42 +080056import android.widget.Toast;
57
58import com.android.camera.gallery.IImage;
59import com.android.camera.gallery.IImageList;
60import com.android.camera.gallery.VideoObject;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080061
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +080062import java.util.ArrayList;
Owen Linb5d87cf2009-04-22 07:58:43 +080063import java.util.HashSet;
64
Ray Chen91acb5b2009-04-24 12:12:04 +080065public class ImageGallery extends Activity implements
Owen Linb5d87cf2009-04-22 07:58:43 +080066 GridViewSpecial.Listener, GridViewSpecial.DrawAdapter {
Owen Lin0e27f8d2009-04-29 01:11:45 -070067 private static final String STATE_SCROLL_POSITION = "scroll_position";
68 private static final String STATE_SELECTED_INDEX = "first_index";
69
Ray Chen91acb5b2009-04-24 12:12:04 +080070 private static final String TAG = "ImageGallery";
Owen Lin0e27f8d2009-04-29 01:11:45 -070071 private static final float INVALID_POSITION = -1f;
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +080072 private ImageManager.ImageListParam mParam;
Owen Lin0e27f8d2009-04-29 01:11:45 -070073 private IImageList mAllImages;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080074 private int mInclusion;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070075 boolean mSortAscending = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080076 private View mNoImagesView;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -070077 public static final int CROP_MSG = 2;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080078
79 private Dialog mMediaScanningDialog;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080080 private MenuItem mSlideShowItem;
81 private SharedPreferences mPrefs;
82 private long mVideoSizeLimit = Long.MAX_VALUE;
Owen Lin228f1322009-04-23 16:24:26 -070083 private View mFooterOrganizeView;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080084
Owen Lin0e27f8d2009-04-29 01:11:45 -070085 private BroadcastReceiver mReceiver = null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080086
Owen Lin0e27f8d2009-04-29 01:11:45 -070087 private final Handler mHandler = new Handler();
88 private boolean mLayoutComplete;
Chih-Chung Changa3be1aa2009-05-11 19:09:14 +080089 private boolean mPausing = true;
Chih-Chung Chang605f7e62009-05-21 11:05:38 +080090 private ImageLoader mLoader;
91 private GridViewSpecial mGvs;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080092
Chih-Chung Chang605f7e62009-05-21 11:05:38 +080093 private Uri mCropResultUri;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080094
Owen Linf310a3d2009-04-20 14:05:17 +080095 // The index of the first picture in GridViewSpecial.
Owen Lin4c2f8572009-07-08 15:13:54 -070096 private int mSelectedIndex = GridViewSpecial.INDEX_NONE;
Owen Lin0e27f8d2009-04-29 01:11:45 -070097 private float mScrollPosition = INVALID_POSITION;
98 private boolean mConfigurationChanged = false;
Owen Linf310a3d2009-04-20 14:05:17 +080099
Owen Linb5d87cf2009-04-22 07:58:43 +0800100 private HashSet<IImage> mMultiSelected = null;
101
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800102 @Override
103 public void onCreate(Bundle icicle) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800104 super.onCreate(icicle);
105
106 mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
107
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700108 // Must be called before setContentView().
109 requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
110
Owen Lin8f8cf382009-07-29 13:45:42 +0800111 setContentView(R.layout.image_gallery);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800112
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700113 getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
114 R.layout.custom_gallery_title);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800115
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800116 mNoImagesView = findViewById(R.id.no_images);
117
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800118 mGvs = (GridViewSpecial) findViewById(R.id.grid);
Owen Linf310a3d2009-04-20 14:05:17 +0800119 mGvs.setListener(this);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800120
Owen Lin228f1322009-04-23 16:24:26 -0700121 mFooterOrganizeView = findViewById(R.id.footer_organize);
122
Owen Lin601ce562009-04-29 17:47:19 -0700123 // consume all click events on the footer view
124 mFooterOrganizeView.setOnClickListener(Util.getNullOnClickListener());
125 initializeFooterButtons();
126
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800127 if (isPickIntent()) {
128 mVideoSizeLimit = getIntent().getLongExtra(
129 MediaStore.EXTRA_SIZE_LIMIT, Long.MAX_VALUE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800130 } else {
131 mVideoSizeLimit = Long.MAX_VALUE;
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700132 mGvs.setOnCreateContextMenuListener(
133 new CreateContextMenuListener());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800134 }
Chih-Chung Changff9922f2009-04-27 19:43:36 +0800135
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800136 setupInclusion();
137
Ray Chenbde544f2009-09-30 14:33:15 -0700138 mLoader = new ImageLoader(getContentResolver(), mHandler);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800139 }
140
Owen Lin601ce562009-04-29 17:47:19 -0700141 private void initializeFooterButtons() {
142 Button deleteButton = (Button) findViewById(R.id.button_delete);
143 deleteButton.setOnClickListener(new OnClickListener() {
Owen Lin601ce562009-04-29 17:47:19 -0700144 public void onClick(View v) {
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800145 onDeleteMultipleClicked();
Owen Lin601ce562009-04-29 17:47:19 -0700146 }
147 });
148
Owen Lin8f8cf382009-07-29 13:45:42 +0800149 Button shareButton = (Button) findViewById(R.id.button_share);
150 shareButton.setOnClickListener(new OnClickListener() {
151 public void onClick(View v) {
152 onShareMultipleClicked();
153 }
154 });
155
Owen Lin601ce562009-04-29 17:47:19 -0700156 Button closeButton = (Button) findViewById(R.id.button_close);
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800157 closeButton.setOnClickListener(new OnClickListener() {
Owen Lin601ce562009-04-29 17:47:19 -0700158 public void onClick(View v) {
159 closeMultiSelectMode();
160 }
161 });
162 }
163
Chih-Chung Changd1890832009-09-08 13:32:52 +0800164 private MenuItem addSlideShowMenu(Menu menu) {
165 return menu.add(Menu.NONE, Menu.NONE, MenuHelper.POSITION_SLIDESHOW,
166 R.string.slide_show)
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700167 .setOnMenuItemClickListener(
168 new MenuItem.OnMenuItemClickListener() {
169 public boolean onMenuItemClick(MenuItem item) {
170 return onSlideShowClicked();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800171 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700172 }).setIcon(android.R.drawable.ic_menu_slideshow);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800173 }
174
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700175 public boolean onSlideShowClicked() {
repo synccd340012009-06-02 12:32:33 +0800176 if (!canHandleEvent()) {
177 return false;
178 }
Owen Linf310a3d2009-04-20 14:05:17 +0800179 IImage img = getCurrentImage();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700180 if (img == null) {
181 img = mAllImages.getImageAt(0);
182 if (img == null) {
183 return true;
184 }
185 }
186 Uri targetUri = img.fullSizeImageUri();
187 Uri thisUri = getIntent().getData();
188 if (thisUri != null) {
189 String bucket = thisUri.getQueryParameter("bucketId");
190 if (bucket != null) {
191 targetUri = targetUri.buildUpon()
192 .appendQueryParameter("bucketId", bucket)
193 .build();
194 }
195 }
196 Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
197 intent.putExtra("slideshow", true);
198 startActivity(intent);
199 return true;
200 }
Owen Lin937fc482009-04-14 02:02:51 -0700201
Chih-Chung Chang74be0522009-04-14 18:00:10 +0800202 private final Runnable mDeletePhotoRunnable = new Runnable() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800203 public void run() {
Chih-Chung Chang18091362009-06-16 12:11:31 +0800204 if (!canHandleEvent()) return;
Chih-Chung Chang30f17b22009-06-29 15:24:13 +0800205
Owen Linf310a3d2009-04-20 14:05:17 +0800206 IImage currentImage = getCurrentImage();
Chih-Chung Chang05f863c2009-07-10 13:16:22 +0800207
208 // The selection will be cleared when mGvs.stop() is called, so
209 // we need to call getCurrentImage() before mGvs.stop().
210 mGvs.stop();
211
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800212 if (currentImage != null) {
213 mAllImages.removeImage(currentImage);
214 }
Chih-Chung Changa3be1aa2009-05-11 19:09:14 +0800215 mGvs.setImageList(mAllImages);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800216 mGvs.start();
Chih-Chung Chang30f17b22009-06-29 15:24:13 +0800217
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700218 mNoImagesView.setVisibility(mAllImages.isEmpty()
219 ? View.VISIBLE
220 : View.GONE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800221 }
222 };
223
Owen Linf310a3d2009-04-20 14:05:17 +0800224 private Uri getCurrentImageUri() {
225 IImage image = getCurrentImage();
226 if (image != null) {
227 return image.fullSizeImageUri();
228 } else {
229 return null;
230 }
231 }
232
233 private IImage getCurrentImage() {
Chih-Chung Changa3be1aa2009-05-11 19:09:14 +0800234 int currentSelection = mGvs.getCurrentSelection();
Owen Linf310a3d2009-04-20 14:05:17 +0800235 if (currentSelection < 0
236 || currentSelection >= mAllImages.getCount()) {
237 return null;
238 } else {
239 return mAllImages.getImageAt(currentSelection);
240 }
241 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800242
243 @Override
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700244 public void onConfigurationChanged(Configuration newConfig) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800245 super.onConfigurationChanged(newConfig);
Owen Lin0e27f8d2009-04-29 01:11:45 -0700246 mConfigurationChanged = true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800247 }
248
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700249 boolean canHandleEvent() {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700250 // Don't process event in pause state.
Owen Linf310a3d2009-04-20 14:05:17 +0800251 return (!mPausing) && (mLayoutComplete);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800252 }
Owen Lin937fc482009-04-14 02:02:51 -0700253
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800254 @Override
255 public boolean onKeyDown(int keyCode, KeyEvent event) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700256 if (!canHandleEvent()) return false;
Owen Linf310a3d2009-04-20 14:05:17 +0800257 switch (keyCode) {
258 case KeyEvent.KEYCODE_DEL:
Chih-Chung Changc476b252009-07-02 17:18:24 +0800259 IImage image = getCurrentImage();
260 if (image != null) {
261 MenuHelper.deleteImage(
262 this, mDeletePhotoRunnable, getCurrentImage());
263 }
Owen Linf310a3d2009-04-20 14:05:17 +0800264 return true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800265 }
Owen Linf310a3d2009-04-20 14:05:17 +0800266 return super.onKeyDown(keyCode, event);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800267 }
268
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800269 private boolean isPickIntent() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800270 String action = getIntent().getAction();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700271 return (Intent.ACTION_PICK.equals(action)
272 || Intent.ACTION_GET_CONTENT.equals(action));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800273 }
274
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800275 private void launchCropperOrFinish(IImage img) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800276 Bundle myExtras = getIntent().getExtras();
277
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800278 long size = MenuHelper.getImageFileSize(img);
279 if (size < 0) {
Wu-cheng Li84635832009-05-07 16:07:10 +0800280 // Return if the image file is not available.
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800281 return;
282 }
Owen Lin937fc482009-04-14 02:02:51 -0700283
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800284 if (size > mVideoSizeLimit) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800285 DialogInterface.OnClickListener buttonListener =
286 new DialogInterface.OnClickListener() {
287 public void onClick(DialogInterface dialog, int which) {
288 dialog.dismiss();
289 }
290 };
291 new AlertDialog.Builder(this)
292 .setIcon(android.R.drawable.ic_dialog_info)
293 .setTitle(R.string.file_info_title)
294 .setMessage(R.string.video_exceed_mms_limit)
295 .setNeutralButton(R.string.details_ok, buttonListener)
296 .show();
297 return;
298 }
299
300 String cropValue = myExtras != null ? myExtras.getString("crop") : null;
301 if (cropValue != null) {
302 Bundle newExtras = new Bundle();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700303 if (cropValue.equals("circle")) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800304 newExtras.putString("circleCrop", "true");
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700305 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800306
307 Intent cropIntent = new Intent();
308 cropIntent.setData(img.fullSizeImageUri());
309 cropIntent.setClass(this, CropImage.class);
310 cropIntent.putExtras(newExtras);
311
312 /* pass through any extras that were passed in */
313 cropIntent.putExtras(myExtras);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800314 startActivityForResult(cropIntent, CROP_MSG);
315 } else {
316 Intent result = new Intent(null, img.fullSizeImageUri());
Wu-cheng Li84635832009-05-07 16:07:10 +0800317 if (myExtras != null && myExtras.getBoolean("return-data")) {
318 // The size of a transaction should be below 100K.
Chih-Chung Changce033a52009-07-27 13:03:29 +0800319 Bitmap bitmap = img.fullSizeBitmap(
320 IImage.UNCONSTRAINED, 100 * 1024);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700321 if (bitmap != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800322 result.putExtra("data", bitmap);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700323 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800324 }
325 setResult(RESULT_OK, result);
326 finish();
327 }
328 }
329
330 @Override
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700331 protected void onActivityResult(int requestCode, int resultCode,
332 Intent data) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800333 switch (requestCode) {
334 case MenuHelper.RESULT_COMMON_MENU_CROP: {
335 if (resultCode == RESULT_OK) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700336
337 // The CropImage activity passes back the Uri of the cropped
338 // image as the Action rather than the Data.
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800339 // We store this URI so we can move the selection box to it
340 // later.
341 mCropResultUri = Uri.parse(data.getAction());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800342 }
343 break;
344 }
345 case CROP_MSG: {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800346 if (resultCode == RESULT_OK) {
347 setResult(resultCode, data);
348 finish();
349 }
350 break;
351 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800352 }
353 }
354
355 @Override
356 public void onPause() {
357 super.onPause();
358 mPausing = true;
Owen Lin937fc482009-04-14 02:02:51 -0700359
Ray Chen896182a2009-05-13 16:21:52 +0800360 mLoader.stop();
361
Owen Linf310a3d2009-04-20 14:05:17 +0800362 mGvs.stop();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800363
364 if (mReceiver != null) {
365 unregisterReceiver(mReceiver);
366 mReceiver = null;
367 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700368
369 // Now that we've paused the threads that are using the cursor it is
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800370 // safe to close it.
371 mAllImages.close();
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800372 mAllImages = null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800373 }
374
375 private void rebake(boolean unmounted, boolean scanning) {
Chih-Chung Changa3be1aa2009-05-11 19:09:14 +0800376 mGvs.stop();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800377 if (mAllImages != null) {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800378 mAllImages.close();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800379 mAllImages = null;
380 }
repo sync62ca1912009-07-01 18:37:14 +0800381
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800382 if (mMediaScanningDialog != null) {
383 mMediaScanningDialog.cancel();
384 mMediaScanningDialog = null;
385 }
repo sync62ca1912009-07-01 18:37:14 +0800386
Ray Chen2f84ae82009-07-08 16:54:54 +0800387 if (scanning) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800388 mMediaScanningDialog = ProgressDialog.show(
389 this,
390 null,
391 getResources().getString(R.string.wait),
392 true,
393 true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800394 }
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800395
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800396 mParam = allImages(!unmounted && !scanning);
397 mAllImages = ImageManager.makeImageList(getContentResolver(), mParam);
Ray Chen2f84ae82009-07-08 16:54:54 +0800398
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800399 mGvs.setImageList(mAllImages);
400 mGvs.setDrawAdapter(this);
401 mGvs.setLoader(mLoader);
402 mGvs.start();
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800403 mNoImagesView.setVisibility(mAllImages.getCount() > 0
404 ? View.GONE
405 : View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800406 }
407
408 @Override
409 protected void onSaveInstanceState(Bundle state) {
410 super.onSaveInstanceState(state);
Owen Lin0e27f8d2009-04-29 01:11:45 -0700411 state.putFloat(STATE_SCROLL_POSITION, mScrollPosition);
412 state.putInt(STATE_SELECTED_INDEX, mSelectedIndex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800413 }
414
415 @Override
416 protected void onRestoreInstanceState(Bundle state) {
417 super.onRestoreInstanceState(state);
Owen Lin0e27f8d2009-04-29 01:11:45 -0700418 mScrollPosition = state.getFloat(
419 STATE_SCROLL_POSITION, INVALID_POSITION);
420 mSelectedIndex = state.getInt(STATE_SELECTED_INDEX, 0);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800421 }
422
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800423 @Override
424 public void onResume() {
425 super.onResume();
Owen Lin937fc482009-04-14 02:02:51 -0700426
Owen Linf310a3d2009-04-20 14:05:17 +0800427 mGvs.setSizeChoice(Integer.parseInt(
Owen Lin0e27f8d2009-04-29 01:11:45 -0700428 mPrefs.getString("pref_gallery_size_key", "1")));
Owen Linf310a3d2009-04-20 14:05:17 +0800429 mGvs.requestFocus();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800430
Owen Linf310a3d2009-04-20 14:05:17 +0800431 String sortOrder = mPrefs.getString("pref_gallery_sort_key", null);
432 if (sortOrder != null) {
433 mSortAscending = sortOrder.equals("ascending");
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800434 }
Owen Linf310a3d2009-04-20 14:05:17 +0800435
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800436 mPausing = false;
437
438 // install an intent filter to receive SD card related events.
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700439 IntentFilter intentFilter =
440 new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800441 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
442 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
443 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
444 intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
445 intentFilter.addDataScheme("file");
446
447 mReceiver = new BroadcastReceiver() {
448 @Override
449 public void onReceive(Context context, Intent intent) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800450 String action = intent.getAction();
451 if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
452 // SD card available
453 // TODO put up a "please wait" message
454 // TODO also listen for the media scanner finished message
455 } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
456 // SD card unavailable
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800457 rebake(true, false);
458 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800459 rebake(false, true);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700460 } else if (action.equals(
461 Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800462 rebake(false, false);
463 } else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800464 rebake(true, false);
465 }
466 }
467 };
468 registerReceiver(mReceiver, intentFilter);
Chih-Chung Changa6e21442009-04-17 23:18:09 +0800469 rebake(false, ImageManager.isMediaScannerScanning(
470 getContentResolver()));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800471 }
472
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800473 @Override
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800474 public boolean onCreateOptionsMenu(Menu menu) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700475 if (isPickIntent()) {
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800476 String type = getIntent().resolveType(this);
477 if (type != null) {
478 if (isImageType(type)) {
479 MenuHelper.addCapturePictureMenuItems(menu, this);
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800480 } else if (isVideoType(type)) {
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800481 MenuHelper.addCaptureVideoMenuItems(menu, this);
482 }
483 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700484 } else {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800485 MenuHelper.addCaptureMenuItems(menu, this);
486 if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
Chih-Chung Changd1890832009-09-08 13:32:52 +0800487 mSlideShowItem = addSlideShowMenu(menu);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800488 }
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800489
Chih-Chung Changd1890832009-09-08 13:32:52 +0800490 MenuItem item = menu.add(Menu.NONE, Menu.NONE,
491 MenuHelper.POSITION_GALLERY_SETTING,
492 R.string.camerasettings);
Owen Linb5d87cf2009-04-22 07:58:43 +0800493 item.setOnMenuItemClickListener(
494 new MenuItem.OnMenuItemClickListener() {
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800495 public boolean onMenuItemClick(MenuItem item) {
496 Intent preferences = new Intent();
Chih-Chung Chang6b270502009-04-29 11:57:06 +0800497 preferences.setClass(ImageGallery.this,
498 GallerySettings.class);
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800499 startActivity(preferences);
500 return true;
501 }
502 });
503 item.setAlphabeticShortcut('p');
504 item.setIcon(android.R.drawable.ic_menu_preferences);
Owen Linb5d87cf2009-04-22 07:58:43 +0800505
Chih-Chung Changd1890832009-09-08 13:32:52 +0800506 item = menu.add(Menu.NONE, Menu.NONE,
507 MenuHelper.POSITION_MULTISELECT,
508 R.string.multiselect);
Owen Linb5d87cf2009-04-22 07:58:43 +0800509 item.setOnMenuItemClickListener(
510 new MenuItem.OnMenuItemClickListener() {
511 public boolean onMenuItemClick(MenuItem item) {
Owen Lin601ce562009-04-29 17:47:19 -0700512 if (isInMultiSelectMode()) {
513 closeMultiSelectMode();
Owen Linb5d87cf2009-04-22 07:58:43 +0800514 } else {
Owen Lin601ce562009-04-29 17:47:19 -0700515 openMultiSelectMode();
Owen Linb5d87cf2009-04-22 07:58:43 +0800516 }
Owen Linb5d87cf2009-04-22 07:58:43 +0800517 return true;
518 }
519 });
520 item.setIcon(R.drawable.ic_menu_multiselect_gallery);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800521 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800522 return true;
523 }
524
525 @Override
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800526 public boolean onPrepareOptionsMenu(Menu menu) {
Chih-Chung Chang938aad02009-05-22 13:32:46 +0800527 if (!canHandleEvent()) return false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800528 if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
529 boolean videoSelected = isVideoSelected();
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700530 // TODO: Only enable slide show if there is at least one image in
531 // the folder.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800532 if (mSlideShowItem != null) {
533 mSlideShowItem.setEnabled(!videoSelected);
534 }
535 }
536
537 return true;
538 }
539
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800540 private boolean isVideoSelected() {
Owen Linf310a3d2009-04-20 14:05:17 +0800541 IImage image = getCurrentImage();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800542 return (image != null) && ImageManager.isVideo(image);
543 }
544
Chih-Chung Chang02e2b0b2009-04-20 12:06:53 +0800545 private boolean isImageType(String type) {
546 return type.equals("vnd.android.cursor.dir/image")
547 || type.equals("image/*");
548 }
549
550 private boolean isVideoType(String type) {
551 return type.equals("vnd.android.cursor.dir/video")
552 || type.equals("video/*");
553 }
554
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800555 // According to the intent, setup what we include (image/video) in the
556 // gallery and the title of the gallery.
557 private void setupInclusion() {
558 mInclusion = ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800559
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800560 Intent intent = getIntent();
561 if (intent != null) {
562 String type = intent.resolveType(this);
563 TextView leftText = (TextView) findViewById(R.id.left_text);
564 if (type != null) {
565 if (isImageType(type)) {
566 mInclusion = ImageManager.INCLUDE_IMAGES;
567 if (isPickIntent()) {
568 leftText.setText(R.string.pick_photos_gallery_title);
569 } else {
570 leftText.setText(R.string.photos_gallery_title);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800571 }
572 }
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800573 if (isVideoType(type)) {
574 mInclusion = ImageManager.INCLUDE_VIDEOS;
575 if (isPickIntent()) {
576 leftText.setText(R.string.pick_videos_gallery_title);
577 } else {
578 leftText.setText(R.string.videos_gallery_title);
579 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800580 }
581 }
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800582 Bundle extras = intent.getExtras();
583 String title = (extras != null)
584 ? extras.getString("windowTitle")
585 : null;
586 if (title != null && title.length() > 0) {
587 leftText.setText(title);
588 }
589
590 if (extras != null) {
591 mInclusion = (ImageManager.INCLUDE_IMAGES
592 | ImageManager.INCLUDE_VIDEOS)
593 & extras.getInt("mediaTypes", mInclusion);
594 }
595
596 if (extras != null && extras.getBoolean("pick-drm")) {
597 Log.d(TAG, "pick-drm is true");
598 mInclusion = ImageManager.INCLUDE_DRM_IMAGES;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800599 }
600 }
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800601 }
602
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800603 // Returns the image list parameter which contains the subset of image/video
604 // we want.
605 private ImageManager.ImageListParam allImages(boolean storageAvailable) {
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800606 if (!storageAvailable) {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800607 return ImageManager.getEmptyImageListParam();
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800608 } else {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800609 Uri uri = getIntent().getData();
610 return ImageManager.getImageListParam(
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800611 ImageManager.DataLocation.EXTERNAL,
612 mInclusion,
613 mSortAscending
614 ? ImageManager.SORT_ASCENDING
615 : ImageManager.SORT_DESCENDING,
616 (uri != null)
617 ? uri.getQueryParameter("bucketId")
618 : null);
619 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800620 }
621
Owen Lin4c2f8572009-07-08 15:13:54 -0700622 private void toggleMultiSelected(IImage image) {
623 int original = mMultiSelected.size();
624 if (!mMultiSelected.add(image)) {
625 mMultiSelected.remove(image);
626 }
627 mGvs.invalidate();
628 if (original == 0) showFooter();
629 if (mMultiSelected.size() == 0) hideFooter();
Owen Lin0e27f8d2009-04-29 01:11:45 -0700630 }
631
632 public void onImageClicked(int index) {
Owen Lin4c2f8572009-07-08 15:13:54 -0700633 if (index < 0 || index >= mAllImages.getCount()) {
634 return;
635 }
636 mSelectedIndex = index;
637 mGvs.setSelectedIndex(index);
Owen Linb5d87cf2009-04-22 07:58:43 +0800638
Owen Lin4c2f8572009-07-08 15:13:54 -0700639 IImage image = mAllImages.getImageAt(index);
640
641 if (isInMultiSelectMode()) {
642 toggleMultiSelected(image);
643 return;
644 }
645
646 if (isPickIntent()) {
647 launchCropperOrFinish(image);
648 } else {
649 Intent intent;
650 if (image instanceof VideoObject) {
651 intent = new Intent(
652 Intent.ACTION_VIEW, image.fullSizeImageUri());
653 intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
654 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Chih-Chung Chang74be0522009-04-14 18:00:10 +0800655 } else {
Owen Lin4c2f8572009-07-08 15:13:54 -0700656 intent = new Intent(this, ViewImage.class);
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +0800657 intent.putExtra(ViewImage.KEY_IMAGE_LIST, mParam);
Owen Lin4c2f8572009-07-08 15:13:54 -0700658 intent.setData(image.fullSizeImageUri());
Chih-Chung Chang74be0522009-04-14 18:00:10 +0800659 }
Owen Lin4c2f8572009-07-08 15:13:54 -0700660 startActivity(intent);
661 }
662 }
663
664 public void onImageTapped(int index) {
665 // In the multiselect mode, once the finger finishes tapping, we hide
666 // the selection box by setting the selected index to none. However, if
667 // we use the dpad center key, we will keep the selected index in order
668 // to show the the selection box. We do this because we have the
Chih-Chung Chang9b93bcb2009-09-04 19:46:14 +0800669 // multiselect marker on the images to indicate which of them are
670 // selected, so we don't need the selection box, but in the dpad case
671 // we still need the selection box to show as a "cursor".
Owen Lin4c2f8572009-07-08 15:13:54 -0700672
673 if (isInMultiSelectMode()) {
674 mGvs.setSelectedIndex(GridViewSpecial.INDEX_NONE);
675 toggleMultiSelected(mAllImages.getImageAt(index));
676 } else {
677 onImageClicked(index);
Chih-Chung Chang74be0522009-04-14 18:00:10 +0800678 }
679 }
680
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700681 private class CreateContextMenuListener implements
682 View.OnCreateContextMenuListener {
683 public void onCreateContextMenu(ContextMenu menu, View v,
684 ContextMenu.ContextMenuInfo menuInfo) {
Chih-Chung Chang938aad02009-05-22 13:32:46 +0800685 if (!canHandleEvent()) return;
686
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800687 IImage image = getCurrentImage();
688
689 if (image == null) {
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700690 return;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800691 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800692
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800693 boolean isImage = ImageManager.isImage(image);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700694 if (isImage) {
Chih-Chung Changd1890832009-09-08 13:32:52 +0800695 menu.add(R.string.view)
696 .setOnMenuItemClickListener(
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700697 new MenuItem.OnMenuItemClickListener() {
698 public boolean onMenuItemClick(MenuItem item) {
Chih-Chung Chang0b803c02009-06-24 15:14:33 +0800699 if (!canHandleEvent()) return false;
Chih-Chung Changa3be1aa2009-05-11 19:09:14 +0800700 onImageClicked(mGvs.getCurrentSelection());
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700701 return true;
702 }
703 });
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800704 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700705
706 menu.setHeaderTitle(isImage
707 ? R.string.context_menu_header
708 : R.string.video_context_menu_header);
709 if ((mInclusion & (ImageManager.INCLUDE_IMAGES
710 | ImageManager.INCLUDE_VIDEOS)) != 0) {
711 MenuHelper.MenuItemsResult r = MenuHelper.addImageMenuItems(
712 menu,
713 MenuHelper.INCLUDE_ALL,
Ray Chen91acb5b2009-04-24 12:12:04 +0800714 ImageGallery.this,
Ray Chen993105a2009-04-10 02:11:35 -0700715 mHandler,
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700716 mDeletePhotoRunnable,
717 new MenuHelper.MenuInvoker() {
718 public void run(MenuHelper.MenuCallback cb) {
repo synccd340012009-06-02 12:32:33 +0800719 if (!canHandleEvent()) {
720 return;
721 }
Owen Linf310a3d2009-04-20 14:05:17 +0800722 cb.run(getCurrentImageUri(), getCurrentImage());
Ray Chen92eedd62009-07-15 18:38:29 +0800723 mGvs.invalidateImage(mGvs.getCurrentSelection());
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700724 }
725 });
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800726
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700727 if (r != null) {
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800728 r.gettingReadyToOpen(menu, image);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700729 }
730
731 if (isImage) {
Chih-Chung Chang120bf582009-09-07 18:51:47 +0800732 MenuHelper.enableShowOnMapMenuItem(
733 menu, MenuHelper.hasLatLngData(image));
Chih-Chung Changd1890832009-09-08 13:32:52 +0800734 addSlideShowMenu(menu);
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700735 }
736 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800737 }
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -0700738 }
Owen Linf310a3d2009-04-20 14:05:17 +0800739
Owen Lin0e27f8d2009-04-29 01:11:45 -0700740 public void onLayoutComplete(boolean changed) {
Owen Linf310a3d2009-04-20 14:05:17 +0800741 mLayoutComplete = true;
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800742 if (mCropResultUri != null) {
743 IImage image = mAllImages.getImageForUri(mCropResultUri);
744 mCropResultUri = null;
745 if (image != null) {
Owen Linbbc2f2f2009-05-05 22:11:15 -0700746 mSelectedIndex = mAllImages.getImageIndex(image);
Chih-Chung Chang605f7e62009-05-21 11:05:38 +0800747 }
748 }
Owen Lin4c2f8572009-07-08 15:13:54 -0700749 mGvs.setSelectedIndex(mSelectedIndex);
Owen Lin0e27f8d2009-04-29 01:11:45 -0700750 if (mScrollPosition == INVALID_POSITION) {
751 if (mSortAscending) {
752 mGvs.scrollTo(0, mGvs.getHeight());
753 } else {
754 mGvs.scrollToImage(0);
755 }
756 } else if (mConfigurationChanged) {
757 mConfigurationChanged = false;
758 mGvs.scrollTo(mScrollPosition);
Owen Lin4c2f8572009-07-08 15:13:54 -0700759 if (mGvs.getCurrentSelection() != GridViewSpecial.INDEX_NONE) {
Owen Lin0e27f8d2009-04-29 01:11:45 -0700760 mGvs.scrollToVisible(mSelectedIndex);
761 }
Owen Linf310a3d2009-04-20 14:05:17 +0800762 } else {
Owen Lin0e27f8d2009-04-29 01:11:45 -0700763 mGvs.scrollTo(mScrollPosition);
Owen Linf310a3d2009-04-20 14:05:17 +0800764 }
765 }
766
Owen Lin0e27f8d2009-04-29 01:11:45 -0700767 public void onScroll(float scrollPosition) {
768 mScrollPosition = scrollPosition;
Owen Linf310a3d2009-04-20 14:05:17 +0800769 }
770
Owen Linb5d87cf2009-04-22 07:58:43 +0800771 private Drawable mVideoOverlay;
772 private Drawable mVideoMmsErrorOverlay;
773 private Drawable mMultiSelectTrue;
Owen Lin228f1322009-04-23 16:24:26 -0700774 private Drawable mMultiSelectFalse;
Owen Linb5d87cf2009-04-22 07:58:43 +0800775
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800776 // mSrcRect and mDstRect are only used in drawImage, but we put them as
777 // instance variables to reduce the memory allocation overhead because
778 // drawImage() is called a lot.
Owen Lindeb57252009-05-27 14:55:45 -0700779 private final Rect mSrcRect = new Rect();
780 private final Rect mDstRect = new Rect();
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800781
Chih-Chung Changdf300712009-09-04 15:54:50 +0800782 private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
783
Owen Linb5d87cf2009-04-22 07:58:43 +0800784 public void drawImage(Canvas canvas, IImage image,
785 Bitmap b, int xPos, int yPos, int w, int h) {
Owen Linb5d87cf2009-04-22 07:58:43 +0800786 if (b != null) {
787 // if the image is close to the target size then crop,
788 // otherwise scale both the bitmap and the view should be
789 // square but I suppose that could change in the future.
790
791 int bw = b.getWidth();
792 int bh = b.getHeight();
793
794 int deltaW = bw - w;
795 int deltaH = bh - h;
796
Chih-Chung Changdf300712009-09-04 15:54:50 +0800797 if (deltaW >= 0 && deltaW < 10 &&
798 deltaH >= 0 && deltaH < 10) {
Owen Linb5d87cf2009-04-22 07:58:43 +0800799 int halfDeltaW = deltaW / 2;
800 int halfDeltaH = deltaH / 2;
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800801 mSrcRect.set(0 + halfDeltaW, 0 + halfDeltaH,
Owen Linb5d87cf2009-04-22 07:58:43 +0800802 bw - halfDeltaW, bh - halfDeltaH);
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800803 mDstRect.set(xPos, yPos, xPos + w, yPos + h);
804 canvas.drawBitmap(b, mSrcRect, mDstRect, null);
Owen Linb5d87cf2009-04-22 07:58:43 +0800805 } else {
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800806 mSrcRect.set(0, 0, bw, bh);
807 mDstRect.set(xPos, yPos, xPos + w, yPos + h);
Chih-Chung Changdf300712009-09-04 15:54:50 +0800808 canvas.drawBitmap(b, mSrcRect, mDstRect, mPaint);
Owen Linb5d87cf2009-04-22 07:58:43 +0800809 }
810 } else {
811 // If the thumbnail cannot be drawn, put up an error icon
812 // instead
813 Bitmap error = getErrorBitmap(image);
814 int width = error.getWidth();
815 int height = error.getHeight();
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800816 mSrcRect.set(0, 0, width, height);
Owen Linb5d87cf2009-04-22 07:58:43 +0800817 int left = (w - width) / 2 + xPos;
818 int top = (w - height) / 2 + yPos;
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800819 mDstRect.set(left, top, left + width, top + height);
820 canvas.drawBitmap(error, mSrcRect, mDstRect, null);
Owen Linb5d87cf2009-04-22 07:58:43 +0800821 }
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800822
Owen Linb5d87cf2009-04-22 07:58:43 +0800823 if (ImageManager.isVideo(image)) {
824 Drawable overlay = null;
825 long size = MenuHelper.getImageFileSize(image);
826 if (size >= 0 && size <= mVideoSizeLimit) {
827 if (mVideoOverlay == null) {
828 mVideoOverlay = getResources().getDrawable(
829 R.drawable.ic_gallery_video_overlay);
830 }
831 overlay = mVideoOverlay;
832 } else {
833 if (mVideoMmsErrorOverlay == null) {
834 mVideoMmsErrorOverlay = getResources().getDrawable(
835 R.drawable.ic_error_mms_video_overlay);
836 }
837 overlay = mVideoMmsErrorOverlay;
Chih-Chung Chang3d6c6282009-04-30 14:35:02 +0800838 Paint paint = new Paint();
Owen Linb5d87cf2009-04-22 07:58:43 +0800839 paint.setARGB(0x80, 0x00, 0x00, 0x00);
840 canvas.drawRect(xPos, yPos, xPos + w, yPos + h, paint);
841 }
842 int width = overlay.getIntrinsicWidth();
843 int height = overlay.getIntrinsicHeight();
844 int left = (w - width) / 2 + xPos;
845 int top = (h - height) / 2 + yPos;
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800846 mSrcRect.set(left, top, left + width, top + height);
847 overlay.setBounds(mSrcRect);
Owen Linb5d87cf2009-04-22 07:58:43 +0800848 overlay.draw(canvas);
849 }
Chih-Chung Changcb4b88e2009-07-07 20:01:55 +0800850 }
Owen Linb5d87cf2009-04-22 07:58:43 +0800851
Chih-Chung Changcb4b88e2009-07-07 20:01:55 +0800852 public boolean needsDecoration() {
853 return (mMultiSelected != null);
854 }
Ray Chen24588aa2009-07-10 18:36:48 +0800855
Chih-Chung Changcb4b88e2009-07-07 20:01:55 +0800856 public void drawDecoration(Canvas canvas, IImage image,
857 int xPos, int yPos, int w, int h) {
Owen Lin228f1322009-04-23 16:24:26 -0700858 if (mMultiSelected != null) {
Owen Linb5d87cf2009-04-22 07:58:43 +0800859 initializeMultiSelectDrawables();
860
Owen Lin228f1322009-04-23 16:24:26 -0700861 Drawable checkBox = mMultiSelected.contains(image)
862 ? mMultiSelectTrue
863 : mMultiSelectFalse;
Owen Linb5d87cf2009-04-22 07:58:43 +0800864 int width = checkBox.getIntrinsicWidth();
865 int height = checkBox.getIntrinsicHeight();
866 int left = 5 + xPos;
867 int top = h - height - 5 + yPos;
Chih-Chung Changdd42edf2009-05-13 17:51:11 +0800868 mSrcRect.set(left, top, left + width, top + height);
869 checkBox.setBounds(mSrcRect);
Owen Linb5d87cf2009-04-22 07:58:43 +0800870 checkBox.draw(canvas);
871 }
872 }
873
874 private void initializeMultiSelectDrawables() {
875 if (mMultiSelectTrue == null) {
876 mMultiSelectTrue = getResources()
877 .getDrawable(R.drawable.btn_check_buttonless_on);
878 }
Owen Lin228f1322009-04-23 16:24:26 -0700879 if (mMultiSelectFalse == null) {
880 mMultiSelectFalse = getResources()
881 .getDrawable(R.drawable.btn_check_buttonless_off);
882 }
Owen Linb5d87cf2009-04-22 07:58:43 +0800883 }
884
885 private Bitmap mMissingImageThumbnailBitmap;
886 private Bitmap mMissingVideoThumbnailBitmap;
887
888 // Create this bitmap lazily, and only once for all the ImageBlocks to
889 // use
890 public Bitmap getErrorBitmap(IImage image) {
891 if (ImageManager.isImage(image)) {
892 if (mMissingImageThumbnailBitmap == null) {
893 mMissingImageThumbnailBitmap = BitmapFactory.decodeResource(
894 getResources(),
895 R.drawable.ic_missing_thumbnail_picture);
896 }
897 return mMissingImageThumbnailBitmap;
898 } else {
899 if (mMissingVideoThumbnailBitmap == null) {
900 mMissingVideoThumbnailBitmap = BitmapFactory.decodeResource(
901 getResources(), R.drawable.ic_missing_thumbnail_video);
902 }
903 return mMissingVideoThumbnailBitmap;
904 }
905 }
Owen Lin228f1322009-04-23 16:24:26 -0700906
907 private Animation mFooterAppear;
908 private Animation mFooterDisappear;
909
910 private void showFooter() {
911 mFooterOrganizeView.setVisibility(View.VISIBLE);
912 if (mFooterAppear == null) {
913 mFooterAppear = AnimationUtils.loadAnimation(
914 this, R.anim.footer_appear);
915 }
916 mFooterOrganizeView.startAnimation(mFooterAppear);
917 }
918
919 private void hideFooter() {
920 if (mFooterOrganizeView.getVisibility() != View.GONE) {
921 mFooterOrganizeView.setVisibility(View.GONE);
922 if (mFooterDisappear == null) {
923 mFooterDisappear = AnimationUtils.loadAnimation(
924 this, R.anim.footer_disappear);
925 }
926 mFooterOrganizeView.startAnimation(mFooterDisappear);
927 }
928 }
Owen Lin601ce562009-04-29 17:47:19 -0700929
Owen Lin8f8cf382009-07-29 13:45:42 +0800930 private String getShareMultipleMimeType() {
931 final int FLAG_IMAGE = 1, FLAG_VIDEO = 2;
932 int flag = 0;
933 for (IImage image : mMultiSelected) {
934 flag |= ImageManager.isImage(image) ? FLAG_IMAGE : FLAG_VIDEO;
935 }
936 return flag == FLAG_IMAGE
937 ? "image/*"
938 : flag == FLAG_VIDEO ? "video/*" : "*/*";
939 }
940
941 private void onShareMultipleClicked() {
Chih-Chung Changc04ffcd2009-10-09 17:40:22 +0800942 if (mMultiSelected == null) return;
Owen Linc0a98e82009-09-04 14:49:05 +0800943 if (mMultiSelected.size() > 1) {
944 Intent intent = new Intent();
945 intent.setAction(Intent.ACTION_SEND_MULTIPLE);
Owen Lin8f8cf382009-07-29 13:45:42 +0800946
Owen Linc0a98e82009-09-04 14:49:05 +0800947 String mimeType = getShareMultipleMimeType();
948 intent.setType(mimeType);
949 ArrayList<Parcelable> list = new ArrayList<Parcelable>();
950 for (IImage image : mMultiSelected) {
951 list.add(image.fullSizeImageUri());
952 }
953 intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, list);
954 try {
955 startActivity(Intent.createChooser(
956 intent, getText(R.string.send_media_files)));
957 } catch (android.content.ActivityNotFoundException ex) {
958 Toast.makeText(this, R.string.no_way_to_share,
959 Toast.LENGTH_SHORT).show();
960 }
961 } else if (mMultiSelected.size() == 1) {
962 IImage image = mMultiSelected.iterator().next();
963 Intent intent = new Intent();
964 intent.setAction(Intent.ACTION_SEND);
965 String mimeType = image.getMimeType();
966 intent.setType(mimeType);
967 intent.putExtra(Intent.EXTRA_STREAM, image.fullSizeImageUri());
968 boolean isImage = ImageManager.isImage(image);
969 try {
970 startActivity(Intent.createChooser(intent, getText(
971 isImage ? R.string.sendImage : R.string.sendVideo)));
972 } catch (android.content.ActivityNotFoundException ex) {
973 Toast.makeText(this, isImage
974 ? R.string.no_way_to_share_image
975 : R.string.no_way_to_share_video,
976 Toast.LENGTH_SHORT).show();
977 }
Owen Lin8f8cf382009-07-29 13:45:42 +0800978 }
979 }
980
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800981 private void onDeleteMultipleClicked() {
982 Runnable action = new Runnable() {
983 public void run() {
984 ArrayList<Uri> uriList = new ArrayList<Uri>();
985 for (IImage image : mMultiSelected) {
986 uriList.add(image.fullSizeImageUri());
Owen Lin601ce562009-04-29 17:47:19 -0700987 }
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800988 closeMultiSelectMode();
989 Intent intent = new Intent(ImageGallery.this,
990 DeleteImage.class);
991 intent.putExtra("delete-uris", uriList);
992 try {
993 startActivity(intent);
994 } catch (ActivityNotFoundException ex) {
995 Log.e(TAG, "Delete images fail", ex);
996 }
Owen Lin601ce562009-04-29 17:47:19 -0700997 }
Owen Lin601ce562009-04-29 17:47:19 -0700998 };
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +0800999 MenuHelper.deleteMultiple(this, action);
Owen Lin601ce562009-04-29 17:47:19 -07001000 }
1001
Owen Lin601ce562009-04-29 17:47:19 -07001002 private boolean isInMultiSelectMode() {
1003 return mMultiSelected != null;
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +08001004 }
Owen Lin601ce562009-04-29 17:47:19 -07001005
1006 private void closeMultiSelectMode() {
1007 if (mMultiSelected == null) return;
1008 mMultiSelected = null;
Chih-Chung Changcb4b88e2009-07-07 20:01:55 +08001009 mGvs.invalidate();
Owen Lin601ce562009-04-29 17:47:19 -07001010 hideFooter();
1011 }
1012
1013 private void openMultiSelectMode() {
1014 if (mMultiSelected != null) return;
1015 mMultiSelected = new HashSet<IImage>();
Chih-Chung Changcb4b88e2009-07-07 20:01:55 +08001016 mGvs.invalidate();
Chih-Chung Chang0e48fe62009-06-26 19:23:56 +08001017 }
Owen Lin4c2f8572009-07-08 15:13:54 -07001018
Chih-Chung Chang9ae6df02009-04-08 01:51:45 -07001019}