blob: 2f296915f6f2b94947641ed78978f9e141b5d870 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera;
import com.android.gallery.R;
import com.android.camera.gallery.IImage;
import com.android.camera.gallery.IImageList;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.StatFs;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* The GalleryPicker activity.
*/
public class GalleryPicker extends NoSearchActivity {
private static final String TAG = "GalleryPicker";
Handler mHandler = new Handler(); // handler for the main thread
Thread mWorkerThread;
BroadcastReceiver mReceiver;
ContentObserver mDbObserver;
GridView mGridView;
GalleryPickerAdapter mAdapter; // mAdapter is only accessed in main thread.
boolean mScanning;
boolean mUnmounted;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.gallerypicker);
mGridView = (GridView) findViewById(R.id.albums);
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
launchFolderGallery(position);
}
});
mGridView.setOnCreateContextMenuListener(
new View.OnCreateContextMenuListener() {
public void onCreateContextMenu(ContextMenu menu, View v,
final ContextMenuInfo menuInfo) {
onCreateGalleryPickerContextMenu(menu, menuInfo);
}
});
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onReceiveMediaBroadcast(intent);
}
};
mDbObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
rebake(false, ImageManager.isMediaScannerScanning(
getContentResolver()));
}
};
ImageManager.ensureOSXCompatibleFolder();
}
Dialog mMediaScanningDialog;
// Display a dialog if the storage is being scanned now.
public void updateScanningDialog(boolean scanning) {
boolean prevScanning = (mMediaScanningDialog != null);
if (prevScanning == scanning && mAdapter.mItems.size() == 0) return;
// Now we are certain the state is changed.
if (prevScanning) {
mMediaScanningDialog.cancel();
mMediaScanningDialog = null;
} else if (scanning && mAdapter.mItems.size() == 0) {
mMediaScanningDialog = ProgressDialog.show(
this,
null,
getResources().getString(R.string.wait),
true,
true);
}
}
private View mNoImagesView;
// Show/Hide the "no images" icon and text. Load resources on demand.
private void showNoImagesView() {
if (mNoImagesView == null) {
ViewGroup root = (ViewGroup) findViewById(R.id.root);
getLayoutInflater().inflate(R.layout.gallerypicker_no_images, root);
mNoImagesView = findViewById(R.id.no_images);
}
mNoImagesView.setVisibility(View.VISIBLE);
}
private void hideNoImagesView() {
if (mNoImagesView != null) {
mNoImagesView.setVisibility(View.GONE);
}
}
// The storage status is changed, restart the worker or show "no images".
private void rebake(boolean unmounted, boolean scanning) {
if (unmounted == mUnmounted && scanning == mScanning) return;
abortWorker();
mUnmounted = unmounted;
mScanning = scanning;
updateScanningDialog(mScanning);
if (mUnmounted) {
showNoImagesView();
} else {
hideNoImagesView();
startWorker();
}
}
// This is called when we receive media-related broadcast.
private void onReceiveMediaBroadcast(Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
// SD card available
// TODO put up a "please wait" message
} else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
// SD card unavailable
rebake(true, false);
} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
rebake(false, true);
} else if (action.equals(
Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
rebake(false, false);
} else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
rebake(true, false);
}
}
private void launchFolderGallery(int position) {
mAdapter.mItems.get(position).launch(this);
}
private void onCreateGalleryPickerContextMenu(ContextMenu menu,
final ContextMenuInfo menuInfo) {
int position = ((AdapterContextMenuInfo) menuInfo).position;
menu.setHeaderTitle(mAdapter.baseTitleForPosition(position));
// "Slide Show"
if ((mAdapter.getIncludeMediaTypes(position)
& ImageManager.INCLUDE_IMAGES) != 0) {
menu.add(R.string.slide_show)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return onSlideShowClicked(menuInfo);
}
});
}
// "View"
menu.add(R.string.view)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return onViewClicked(menuInfo);
}
});
}
// This is called when the user clicks "Slideshow" from the context menu.
private boolean onSlideShowClicked(ContextMenuInfo menuInfo) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
int position = info.position;
if (position < 0 || position >= mAdapter.mItems.size()) {
return true;
}
// Slide show starts from the first image on the list.
Item item = mAdapter.mItems.get(position);
Uri targetUri = item.mFirstImageUri;
if (targetUri != null && item.mBucketId != null) {
targetUri = targetUri.buildUpon()
.appendQueryParameter("bucketId", item.mBucketId)
.build();
}
Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
intent.putExtra("slideshow", true);
startActivity(intent);
return true;
}
// This is called when the user clicks "View" from the context menu.
private boolean onViewClicked(ContextMenuInfo menuInfo) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
launchFolderGallery(info.position);
return true;
}
@Override
public void onStop() {
super.onStop();
abortWorker();
unregisterReceiver(mReceiver);
getContentResolver().unregisterContentObserver(mDbObserver);
// free up some ram
mAdapter = null;
mGridView.setAdapter(null);
unloadDrawable();
}
@Override
public void onStart() {
super.onStart();
mAdapter = new GalleryPickerAdapter(getLayoutInflater());
mGridView.setAdapter(mAdapter);
// install an intent filter to receive SD card related events.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
intentFilter.addDataScheme("file");
registerReceiver(mReceiver, intentFilter);
getContentResolver().registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
true, mDbObserver);
// Assume the storage is mounted and not scanning.
mUnmounted = false;
mScanning = false;
startWorker();
}
// This is used to stop the worker thread.
volatile boolean mAbort = false;
// Create the worker thread.
private void startWorker() {
mAbort = false;
mWorkerThread = new Thread("GalleryPicker Worker") {
@Override
public void run() {
workerRun();
}
};
BitmapManager.instance().allowThreadDecoding(mWorkerThread);
mWorkerThread.start();
}
private void abortWorker() {
if (mWorkerThread != null) {
BitmapManager.instance().cancelThreadDecoding(mWorkerThread, getContentResolver());
mAbort = true;
try {
mWorkerThread.join();
} catch (InterruptedException ex) {
Log.e(TAG, "join interrupted");
}
mWorkerThread = null;
// Remove all runnables in mHandler.
// (We assume that the "what" field in the messages are 0
// for runnables).
mHandler.removeMessages(0);
mAdapter.clear();
mAdapter.updateDisplay();
clearImageLists();
}
}
// This is run in the worker thread.
private void workerRun() {
// We collect items from checkImageList() and checkBucketIds() and
// put them in allItems. Later we give allItems to checkThumbBitmap()
// and generated thumbnail bitmaps for each item. We do this instead of
// generating thumbnail bitmaps in checkImageList() and checkBucketIds()
// because we want to show all the folders first, then update them with
// the thumb bitmaps. (Generating thumbnail bitmaps takes some time.)
ArrayList<Item> allItems = new ArrayList<Item>();
checkScanning();
if (mAbort) return;
checkImageList(allItems);
if (mAbort) return;
checkBucketIds(allItems);
if (mAbort) return;
checkThumbBitmap(allItems);
if (mAbort) return;
checkLowStorage();
}
// This is run in the worker thread.
private void checkScanning() {
ContentResolver cr = getContentResolver();
final boolean scanning =
ImageManager.isMediaScannerScanning(cr);
mHandler.post(new Runnable() {
public void run() {
checkScanningFinished(scanning);
}
});
}
// This is run in the main thread.
private void checkScanningFinished(boolean scanning) {
updateScanningDialog(scanning);
}
// This is run in the worker thread.
private void checkImageList(ArrayList<Item> allItems) {
int length = IMAGE_LIST_DATA.length;
IImageList[] lists = new IImageList[length];
for (int i = 0; i < length; i++) {
ImageListData data = IMAGE_LIST_DATA[i];
lists[i] = createImageList(data.mInclude, data.mBucketId,
getContentResolver());
if (mAbort) return;
Item item = null;
if (lists[i].isEmpty()) continue;
// i >= 3 means we are looking at All Images/All Videos.
// lists[i-3] is the corresponding Camera Images/Camera Videos.
// We want to add the "All" list only if it's different from
// the "Camera" list.
if (i >= 3 && lists[i].getCount() == lists[i - 3].getCount()) {
continue;
}
item = new Item(data.mType,
data.mBucketId,
getResources().getString(data.mStringId),
lists[i]);
allItems.add(item);
final Item finalItem = item;
mHandler.post(new Runnable() {
public void run() {
updateItem(finalItem);
}
});
}
}
// This is run in the main thread.
private void updateItem(Item item) {
// Hide NoImageView if we are going to add the first item
if (mAdapter.getCount() == 0) {
hideNoImagesView();
}
mAdapter.addItem(item);
mAdapter.updateDisplay();
}
private static final String CAMERA_BUCKET =
ImageManager.CAMERA_IMAGE_BUCKET_ID;
// This is run in the worker thread.
private void checkBucketIds(ArrayList<Item> allItems) {
final IImageList allImages;
if (!mScanning && !mUnmounted) {
allImages = ImageManager.makeImageList(
getContentResolver(),
ImageManager.DataLocation.ALL,
ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS,
ImageManager.SORT_DESCENDING,
null);
} else {
allImages = ImageManager.makeEmptyImageList();
}
if (mAbort) {
allImages.close();
return;
}
HashMap<String, String> hashMap = allImages.getBucketIds();
allImages.close();
if (mAbort) return;
for (Map.Entry<String, String> entry : hashMap.entrySet()) {
String key = entry.getKey();
if (key == null) {
continue;
}
if (!key.equals(CAMERA_BUCKET)) {
IImageList list = createImageList(
ImageManager.INCLUDE_IMAGES
| ImageManager.INCLUDE_VIDEOS, key,
getContentResolver());
if (mAbort) return;
Item item = new Item(Item.TYPE_NORMAL_FOLDERS, key,
entry.getValue(), list);
allItems.add(item);
final Item finalItem = item;
mHandler.post(new Runnable() {
public void run() {
updateItem(finalItem);
}
});
}
}
mHandler.post(new Runnable() {
public void run() {
checkBucketIdsFinished();
}
});
}
// This is run in the main thread.
private void checkBucketIdsFinished() {
// If we just have one folder, open it.
// If we have zero folder, show the "no images" icon.
if (!mScanning) {
int numItems = mAdapter.mItems.size();
if (numItems == 0) {
showNoImagesView();
} else if (numItems == 1) {
mAdapter.mItems.get(0).launch(this);
finish();
return;
}
}
}
private static final int THUMB_SIZE = 142;
// This is run in the worker thread.
private void checkThumbBitmap(ArrayList<Item> allItems) {
for (Item item : allItems) {
final Bitmap b = makeMiniThumbBitmap(THUMB_SIZE, THUMB_SIZE,
item.mImageList);
if (mAbort) {
if (b != null) b.recycle();
return;
}
final Item finalItem = item;
mHandler.post(new Runnable() {
public void run() {
updateThumbBitmap(finalItem, b);
}
});
}
}
// This is run in the main thread.
private void updateThumbBitmap(Item item, Bitmap b) {
item.setThumbBitmap(b);
mAdapter.updateDisplay();
}
private static final long LOW_STORAGE_THRESHOLD = 1024 * 1024 * 2;
// This is run in the worker thread.
private void checkLowStorage() {
// Check available space only if we are writable
if (ImageManager.hasStorage()) {
String storageDirectory = Environment
.getExternalStorageDirectory().toString();
StatFs stat = new StatFs(storageDirectory);
long remaining = (long) stat.getAvailableBlocks()
* (long) stat.getBlockSize();
if (remaining < LOW_STORAGE_THRESHOLD) {
mHandler.post(new Runnable() {
public void run() {
checkLowStorageFinished();
}
});
}
}
}
// This is run in the main thread.
// This is called only if the storage is low.
private void checkLowStorageFinished() {
Toast.makeText(GalleryPicker.this, R.string.not_enough_space, 5000)
.show();
}
// IMAGE_LIST_DATA stores the parameters for the four image lists
// we are interested in. The order of the IMAGE_LIST_DATA array is
// significant (See the implementation of GalleryPickerAdapter.init).
private static final class ImageListData {
ImageListData(int type, int include, String bucketId, int stringId) {
mType = type;
mInclude = include;
mBucketId = bucketId;
mStringId = stringId;
}
int mType;
int mInclude;
String mBucketId;
int mStringId;
}
private static final ImageListData[] IMAGE_LIST_DATA = {
// Camera Images
new ImageListData(Item.TYPE_CAMERA_IMAGES,
ImageManager.INCLUDE_IMAGES,
ImageManager.CAMERA_IMAGE_BUCKET_ID,
R.string.gallery_camera_bucket_name),
// Camera Videos
new ImageListData(Item.TYPE_CAMERA_VIDEOS,
ImageManager.INCLUDE_VIDEOS,
ImageManager.CAMERA_IMAGE_BUCKET_ID,
R.string.gallery_camera_videos_bucket_name),
// Camera Medias
new ImageListData(Item.TYPE_CAMERA_MEDIAS,
ImageManager.INCLUDE_VIDEOS | ImageManager.INCLUDE_IMAGES,
ImageManager.CAMERA_IMAGE_BUCKET_ID,
R.string.gallery_camera_media_bucket_name),
// All Images
new ImageListData(Item.TYPE_ALL_IMAGES,
ImageManager.INCLUDE_IMAGES,
null,
R.string.all_images),
// All Videos
new ImageListData(Item.TYPE_ALL_VIDEOS,
ImageManager.INCLUDE_VIDEOS,
null,
R.string.all_videos),
};
// These drawables are loaded on-demand.
Drawable mFrameGalleryMask;
Drawable mCellOutline;
Drawable mVideoOverlay;
private void loadDrawableIfNeeded() {
if (mFrameGalleryMask != null) return; // already loaded
Resources r = getResources();
mFrameGalleryMask = r.getDrawable(
R.drawable.frame_gallery_preview_album_mask);
mCellOutline = r.getDrawable(android.R.drawable.gallery_thumb);
mVideoOverlay = r.getDrawable(R.drawable.ic_gallery_video_overlay);
}
private void unloadDrawable() {
mFrameGalleryMask = null;
mCellOutline = null;
mVideoOverlay = null;
}
private static void placeImage(Bitmap image, Canvas c, Paint paint,
int imageWidth, int widthPadding, int imageHeight,
int heightPadding, int offsetX, int offsetY,
int pos) {
int row = pos / 2;
int col = pos - (row * 2);
int xPos = (col * (imageWidth + widthPadding)) - offsetX;
int yPos = (row * (imageHeight + heightPadding)) - offsetY;
c.drawBitmap(image, xPos, yPos, paint);
}
// This is run in worker thread.
private Bitmap makeMiniThumbBitmap(int width, int height,
IImageList images) {
int count = images.getCount();
// We draw three different version of the folder image depending on the
// number of images in the folder.
// For a single image, that image draws over the whole folder.
// For two or three images, we draw the two most recent photos.
// For four or more images, we draw four photos.
final int padding = 4;
int imageWidth = width;
int imageHeight = height;
int offsetWidth = 0;
int offsetHeight = 0;
imageWidth = (imageWidth - padding) / 2; // 2 here because we show two
// images
imageHeight = (imageHeight - padding) / 2; // per row and column
final Paint p = new Paint();
final Bitmap b = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
final Canvas c = new Canvas(b);
final Matrix m = new Matrix();
// draw the whole canvas as transparent
p.setColor(0x00000000);
c.drawPaint(p);
// load the drawables
loadDrawableIfNeeded();
// draw the mask normally
p.setColor(0xFFFFFFFF);
mFrameGalleryMask.setBounds(0, 0, width, height);
mFrameGalleryMask.draw(c);
Paint pdpaint = new Paint();
pdpaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
pdpaint.setStyle(Paint.Style.FILL);
c.drawRect(0, 0, width, height, pdpaint);
for (int i = 0; i < 4; i++) {
if (mAbort) {
return null;
}
Bitmap temp = null;
IImage image = i < count ? images.getImageAt(i) : null;
if (image != null) {
temp = image.miniThumbBitmap();
}
if (temp != null) {
if (ImageManager.isVideo(image)) {
Bitmap newMap = temp.copy(temp.getConfig(), true);
Canvas overlayCanvas = new Canvas(newMap);
int overlayWidth = mVideoOverlay.getIntrinsicWidth();
int overlayHeight = mVideoOverlay.getIntrinsicHeight();
int left = (newMap.getWidth() - overlayWidth) / 2;
int top = (newMap.getHeight() - overlayHeight) / 2;
Rect newBounds = new Rect(left, top, left + overlayWidth,
top + overlayHeight);
mVideoOverlay.setBounds(newBounds);
mVideoOverlay.draw(overlayCanvas);
temp.recycle();
temp = newMap;
}
temp = Util.transform(m, temp, imageWidth,
imageHeight, true, Util.RECYCLE_INPUT);
}
Bitmap thumb = Bitmap.createBitmap(imageWidth, imageHeight,
Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(thumb);
if (temp != null) {
tempCanvas.drawBitmap(temp, new Matrix(), new Paint());
}
mCellOutline.setBounds(0, 0, imageWidth, imageHeight);
mCellOutline.draw(tempCanvas);
placeImage(thumb, c, pdpaint, imageWidth, padding, imageHeight,
padding, offsetWidth, offsetHeight, i);
thumb.recycle();
if (temp != null) {
temp.recycle();
}
}
return b;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuHelper.addCaptureMenuItems(menu, this);
menu.add(Menu.NONE, Menu.NONE, MenuHelper.POSITION_GALLERY_SETTING,
R.string.camerasettings)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Intent preferences = new Intent();
preferences.setClass(GalleryPicker.this,
GallerySettings.class);
startActivity(preferences);
return true;
}
})
.setAlphabeticShortcut('p')
.setIcon(android.R.drawable.ic_menu_preferences);
return true;
}
// image lists created by createImageList() are collected in mAllLists.
// They will be closed in clearImageList, so they don't hold open files
// on SD card. We will be killed if we don't close files when the SD card
// is unmounted.
ArrayList<IImageList> mAllLists = new ArrayList<IImageList>();
private IImageList createImageList(int mediaTypes, String bucketId,
ContentResolver cr) {
IImageList list = ImageManager.makeImageList(
cr,
ImageManager.DataLocation.ALL,
mediaTypes,
ImageManager.SORT_DESCENDING,
bucketId);
mAllLists.add(list);
return list;
}
private void clearImageLists() {
for (IImageList list : mAllLists) {
list.close();
}
mAllLists.clear();
}
}
// Item is the underlying data for GalleryPickerAdapter.
// It is passed from the activity to the adapter.
class Item {
public static final int TYPE_NONE = -1;
public static final int TYPE_ALL_IMAGES = 0;
public static final int TYPE_ALL_VIDEOS = 1;
public static final int TYPE_CAMERA_IMAGES = 2;
public static final int TYPE_CAMERA_VIDEOS = 3;
public static final int TYPE_CAMERA_MEDIAS = 4;
public static final int TYPE_NORMAL_FOLDERS = 5;
public final int mType;
public final String mBucketId;
public final String mName;
public final IImageList mImageList;
public final int mCount;
public final Uri mFirstImageUri; // could be null if the list is empty
// The thumbnail bitmap is set by setThumbBitmap() later because we want
// to let the user sees the folder icon as soon as possible (and possibly
// select them), then present more detailed information when we have it.
public Bitmap mThumbBitmap; // the thumbnail bitmap for the image list
public Item(int type, String bucketId, String name, IImageList list) {
mType = type;
mBucketId = bucketId;
mName = name;
mImageList = list;
mCount = list.getCount();
if (mCount > 0) {
mFirstImageUri = list.getImageAt(0).fullSizeImageUri();
} else {
mFirstImageUri = null;
}
}
public void setThumbBitmap(Bitmap thumbBitmap) {
mThumbBitmap = thumbBitmap;
}
public boolean needsBucketId() {
return mType >= TYPE_CAMERA_IMAGES;
}
public void launch(Activity activity) {
Uri uri = Images.Media.INTERNAL_CONTENT_URI;
if (needsBucketId()) {
uri = uri.buildUpon()
.appendQueryParameter("bucketId", mBucketId).build();
}
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("windowTitle", mName);
intent.putExtra("mediaTypes", getIncludeMediaTypes());
activity.startActivity(intent);
}
public int getIncludeMediaTypes() {
return convertItemTypeToIncludedMediaType(mType);
}
public static int convertItemTypeToIncludedMediaType(int itemType) {
switch (itemType) {
case TYPE_ALL_IMAGES:
case TYPE_CAMERA_IMAGES:
return ImageManager.INCLUDE_IMAGES;
case TYPE_ALL_VIDEOS:
case TYPE_CAMERA_VIDEOS:
return ImageManager.INCLUDE_VIDEOS;
case TYPE_NORMAL_FOLDERS:
case TYPE_CAMERA_MEDIAS:
default:
return ImageManager.INCLUDE_IMAGES
| ImageManager.INCLUDE_VIDEOS;
}
}
public int getOverlay() {
switch (mType) {
case TYPE_ALL_IMAGES:
case TYPE_CAMERA_IMAGES:
return R.drawable.frame_overlay_gallery_camera;
case TYPE_ALL_VIDEOS:
case TYPE_CAMERA_VIDEOS:
case TYPE_CAMERA_MEDIAS:
return R.drawable.frame_overlay_gallery_video;
case TYPE_NORMAL_FOLDERS:
default:
return R.drawable.frame_overlay_gallery_folder;
}
}
}
class GalleryPickerAdapter extends BaseAdapter {
ArrayList<Item> mItems = new ArrayList<Item>();
LayoutInflater mInflater;
GalleryPickerAdapter(LayoutInflater inflater) {
mInflater = inflater;
}
public void addItem(Item item) {
mItems.add(item);
}
public void updateDisplay() {
notifyDataSetChanged();
}
public void clear() {
mItems.clear();
}
public int getCount() {
return mItems.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
public String baseTitleForPosition(int position) {
return mItems.get(position).mName;
}
public int getIncludeMediaTypes(int position) {
return mItems.get(position).getIncludeMediaTypes();
}
public View getView(final int position, View convertView,
ViewGroup parent) {
View v;
if (convertView == null) {
v = mInflater.inflate(R.layout.gallery_picker_item, null);
} else {
v = convertView;
}
TextView titleView = (TextView) v.findViewById(R.id.title);
GalleryPickerItem iv =
(GalleryPickerItem) v.findViewById(R.id.thumbnail);
Item item = mItems.get(position);
iv.setOverlay(item.getOverlay());
if (item.mThumbBitmap != null) {
iv.setImageBitmap(item.mThumbBitmap);
String title = item.mName + " (" + item.mCount + ")";
titleView.setText(title);
} else {
iv.setImageResource(android.R.color.transparent);
titleView.setText(item.mName);
}
// An workaround due to a bug in TextView. If the length of text is
// different from the previous in convertView, the layout would be
// wrong.
titleView.requestLayout();
return v;
}
}