diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 1d4c75065966c4f6f56900e31f655bfd1b334435 (patch) | |
tree | 5d4526db3153daa63087fcb9384f8bc0659fbd18 /src/com/android/camera/GalleryPicker.java | |
download | LegacyCamera-1d4c75065966c4f6f56900e31f655bfd1b334435.zip LegacyCamera-1d4c75065966c4f6f56900e31f655bfd1b334435.tar.gz LegacyCamera-1d4c75065966c4f6f56900e31f655bfd1b334435.tar.bz2 |
Initial Contribution
Diffstat (limited to 'src/com/android/camera/GalleryPicker.java')
-rw-r--r-- | src/com/android/camera/GalleryPicker.java | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/src/com/android/camera/GalleryPicker.java b/src/com/android/camera/GalleryPicker.java new file mode 100644 index 0000000..9f1664b --- /dev/null +++ b/src/com/android/camera/GalleryPicker.java @@ -0,0 +1,607 @@ +/* + * 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 android.app.Activity; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +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.preference.PreferenceManager; +import android.provider.MediaStore.Images; +import android.util.Config; +import android.util.Log; +import android.util.SparseArray; +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.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; + +public class GalleryPicker extends Activity { + static private final String TAG = "GalleryPicker"; + + GridView mGridView; + Drawable mFrameGalleryMask; + Drawable mCellOutline; + + BroadcastReceiver mReceiver; + GalleryPickerAdapter mAdapter; + + Dialog mMediaScanningDialog; + + MenuItem mFlipItem; + SharedPreferences mPrefs; + + boolean mPausing = false; + + private static long LOW_STORAGE_THRESHOLD = 1024 * 1024 * 2; + + public GalleryPicker() { + } + + private void rebake(boolean unmounted, boolean scanning) { + if (mMediaScanningDialog != null) { + mMediaScanningDialog.cancel(); + mMediaScanningDialog = null; + } + if (scanning) { + mMediaScanningDialog = ProgressDialog.show( + this, + null, + getResources().getString(R.string.wait), + true, + true); + } + mAdapter.notifyDataSetChanged(); + mAdapter.init(!unmounted && !scanning); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mPrefs = PreferenceManager.getDefaultSharedPreferences(this); + + setContentView(R.layout.gallerypicker); + + mGridView = (GridView) findViewById(R.id.albums); + mGridView.setSelector(android.R.color.transparent); + + mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + if (Config.LOGV) Log.v(TAG, "onReceiveIntent " + intent.getAction()); + String action = intent.getAction(); + if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { + // SD card available + // TODO put up a "please wait" message + // TODO also listen for the media scanner finished message + } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) { + // SD card unavailable + if (Config.LOGV) Log.v(TAG, "sd card no longer available"); + Toast.makeText(GalleryPicker.this, getResources().getString(R.string.wait), 5000); + rebake(true, false); + } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) { + Toast.makeText(GalleryPicker.this, getResources().getString(R.string.wait), 5000); + rebake(false, true); + } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) { + if (Config.LOGV) + Log.v(TAG, "rebake because of ACTION_MEDIA_SCANNER_FINISHED"); + rebake(false, false); + } else if (action.equals(Intent.ACTION_MEDIA_EJECT)) { + if (Config.LOGV) + Log.v(TAG, "rebake because of ACTION_MEDIA_EJECT"); + rebake(true, false); + } + } + }; + + 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 ContextMenu.ContextMenuInfo menuInfo) { + menu.setHeaderTitle( + mAdapter.baseTitleForPosition(((AdapterContextMenuInfo)menuInfo).position)); + menu.add(0, 207, 0, R.string.slide_show) + .setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo; + int position = info.position; + + Uri targetUri; + synchronized (mAdapter.mFirstImageUris) { + if (position >= mAdapter.mFirstImageUris.size()) { + // the list of ids does not include the "all" list + targetUri = mAdapter.firstImageUri(mAdapter.mIds.get(position-1)); + } else { + // the mFirstImageUris list includes the "all" uri + targetUri = mAdapter.mFirstImageUris.get(position); + } + } + if (targetUri != null && position > 0) { + targetUri = targetUri.buildUpon().appendQueryParameter("bucketId", mAdapter.mIds.get(info.position-1)).build(); + } +// Log.v(TAG, "URI to launch slideshow " + targetUri); + Intent intent = new Intent(Intent.ACTION_VIEW, targetUri); + intent.putExtra("slideshow", true); + startActivity(intent); + return true; + } + }); + menu.add(0, 208, 0, R.string.view) + .setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo; + launchFolderGallery(info.position); + return true; + } + }); + } + }); + } + + private void launchFolderGallery(int position) { + android.net.Uri uri = Images.Media.INTERNAL_CONTENT_URI; + if (position > 0) { + uri = uri.buildUpon().appendQueryParameter("bucketId", mAdapter.mIds.get(position-1)).build(); + } + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + if (position > 0) { + intent.putExtra("windowTitle", mAdapter.mNames.get(position-1)); + } + startActivity(intent); + } + + class ItemInfo { + Bitmap bitmap; + int count; + int overlayId; + } + + class GalleryPickerAdapter extends BaseAdapter { + ArrayList<String> mIds = new ArrayList<String>(); + ArrayList<String> mNames = new ArrayList<String>(); + ArrayList<Uri> mFirstImageUris = new ArrayList<Uri>(); + + ArrayList<View> mAllViews = new ArrayList<View>(); + SparseArray<ItemInfo> mThumbs = new SparseArray<ItemInfo>(); + + boolean mDone = false; + CameraThread mWorkerThread; + + public void init(boolean assumeMounted) { + mAllViews.clear(); + mThumbs.clear(); + + ImageManager.IImageList images; + if (assumeMounted) { + images = ImageManager.instance().allImages( + GalleryPicker.this, + getContentResolver(), + ImageManager.DataLocation.ALL, + ImageManager.INCLUDE_IMAGES, + ImageManager.SORT_DESCENDING); + } else { + images = ImageManager.instance().emptyImageList(); + } + + mIds.clear(); + mNames.clear(); + mFirstImageUris.clear(); + + if (mWorkerThread != null) { + try { + mDone = true; + if (Config.LOGV) + Log.v(TAG, "about to call join on thread " + mWorkerThread.getId()); + mWorkerThread.join(); + } finally { + mWorkerThread = null; + } + } + + String cameraItem = ImageManager.CAMERA_IMAGE_BUCKET_ID; + final HashMap<String, String> hashMap = images.getBucketIds(); + String cameraBucketId = null; + for (String key : hashMap.keySet()) { + if (key.equals(cameraItem)) { + cameraBucketId = key; + } else { + mIds.add(key); + } + } + images.deactivate(); + notifyDataSetInvalidated(); + + // sort baesd on the display name. if two display names compare equal + // then sort based on the id + java.util.Collections.sort(mIds, new java.util.Comparator<String>() { + public int compare(String first, String second) { + int x = hashMap.get(first).compareTo(hashMap.get(second)); + if (x == 0) + x = first.compareTo(second); + return x; + } + }); + + for (String s : mIds) { + mNames.add(hashMap.get(s)); + } + + if (cameraBucketId != null) { + mIds.add(0, cameraBucketId); + mNames.add(0, "Camera"); + } + final boolean foundCameraBucket = cameraBucketId != null; + + mDone = false; + mWorkerThread = new CameraThread(new Runnable() { + public void run() { + try { + // no images, nothing to do + if (mIds.size() == 0) + return; + + for (int i = 0; i < mIds.size() + 1 && !mDone; i++) { + String id = i == 0 ? null : mIds.get(i-1); + ImageManager.IImageList list = ImageManager.instance().allImages( + GalleryPicker.this, + getContentResolver(), + ImageManager.DataLocation.ALL, + ImageManager.INCLUDE_IMAGES, + ImageManager.SORT_DESCENDING, + id); + try { + if (mPausing) { + break; + } + if (list.getCount() > 0) + mFirstImageUris.add(i, list.getImageAt(0).fullSizeImageUri()); + + int overlay = -1; + if (i == 1 && foundCameraBucket) + overlay = R.drawable.frame_overlay_gallery_camera; + final Bitmap b = makeMiniThumbBitmap(142, 142, list); + final int pos = i; + final int count = list.getCount(); + final int overlayId = overlay; + final Thread currentThread = Thread.currentThread(); + mHandler.post(new Runnable() { + public void run() { + if (mPausing || currentThread != mWorkerThread.realThread()) { + if (b != null) { + b.recycle(); + } + return; + } + + ItemInfo info = new ItemInfo(); + info.bitmap = b; + info.count = count; + info.overlayId = overlayId; + mThumbs.put(pos, info); + + final GridView grid = GalleryPicker.this.mGridView; + final int firstVisible = grid.getFirstVisiblePosition(); + + // Minor optimization -- only notify if the specified position is visible + if ((pos >= firstVisible) && (pos < firstVisible + grid.getChildCount())) { + GalleryPickerAdapter.this.notifyDataSetChanged(); + } + } + }); + } finally { + list.deactivate(); + } + } + } catch (Exception ex) { + Log.e(TAG, "got exception generating collage views " + ex.toString()); + } + } + }); + mWorkerThread.start(); + mWorkerThread.toBackground(); + } + + Uri firstImageUri(String id) { + ImageManager.IImageList list = ImageManager.instance().allImages( + GalleryPicker.this, + getContentResolver(), + ImageManager.DataLocation.ALL, + ImageManager.INCLUDE_IMAGES, + ImageManager.SORT_DESCENDING, + id); + Uri uri = list.getImageAt(0).fullSizeImageUri(); + list.deactivate(); + return uri; + } + + public int getCount() { + return mIds.size() + 1; // add 1 for the everything bucket + } + + public Object getItem(int position) { + return null; + } + + public long getItemId(int position) { + return position; + } + + private String baseTitleForPosition(int position) { + if (position == 0) { + return getResources().getString(R.string.all_images); + } else { + return mNames.get(position-1); + } + } + + public View getView(final int position, View convertView, ViewGroup parent) { + View v; + + if (convertView == null) { + LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.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); + ItemInfo info = mThumbs.get(position); + if (info != null) { + iv.setImageBitmap(info.bitmap); + iv.setOverlay(info.overlayId); + String title = baseTitleForPosition(position) + " (" + info.count + ")"; + titleView.setText(title); + } else { + iv.setImageResource(android.R.color.transparent); + iv.setOverlay(-1); + titleView.setText(baseTitleForPosition(position)); + } + + return v; + } + }; + + @Override + public void onPause() { + super.onPause(); + mPausing = true; + unregisterReceiver(mReceiver); + + // free up some ram + mAdapter = null; + mGridView.setAdapter(null); + System.gc(); + } + + @Override + public void onResume() { + super.onResume(); + mPausing = false; + + mAdapter = new GalleryPickerAdapter(); + mGridView.setAdapter(mAdapter); + setBackgrounds(getResources()); + + boolean scanning = ImageManager.isMediaScannerScanning(this); + rebake(false, scanning); + + // install an intent filter to receive SD card related events. + IntentFilter intentFilter = new IntentFilter(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); + MenuHelper.requestOrientation(this, mPrefs); + + // Warn the user if space is getting low + Thread t = new Thread(new Runnable() { + public void run() { + + // 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() { + Toast.makeText(GalleryPicker.this.getApplicationContext(), + R.string.not_enough_space, 5000).show(); + } + }); + } + } + } + }); + t.start(); + + if (!scanning && mAdapter.mIds.size() <= 1) { + android.net.Uri uri = Images.Media.INTERNAL_CONTENT_URI; + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + startActivity(intent); + finish(); + return; + } + } + + + private void setBackgrounds(Resources r) { + mFrameGalleryMask = r.getDrawable(R.drawable.frame_gallery_preview_album_mask); + + mCellOutline = r.getDrawable(android.R.drawable.gallery_thumb); + } + + Handler mHandler = new Handler(); + + private 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); + } + + private Bitmap makeMiniThumbBitmap(int width, int height, ImageManager.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; + if (count < 4) { + count = 1; + // uncomment for 2 pictures per frame +// if (count == 2 || count == 3) { +// count = 2; +// imageWidth = imageWidth * 2 / 3; +// imageHeight = imageHeight * 2 / 3; +// offsetWidth = imageWidth / 3 - padding; +// offsetHeight = -imageHeight / 3 + padding * 2; + } else if (count >= 4) { + count = 4; + 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); + + // draw the mask normally + p.setColor(0xFFFFFFFF); + mFrameGalleryMask.setBounds(0, 0, width, height); + mFrameGalleryMask.draw(c); + + Paint pdpaint = new Paint(); + pdpaint.setXfermode(new android.graphics.PorterDuffXfermode( + android.graphics.PorterDuff.Mode.SRC_IN)); + + pdpaint.setStyle(Paint.Style.FILL); + c.drawRect(0, 0, width, height, pdpaint); + + for (int i = 0; i < count; i++) { + if (mPausing) { + return null; + } + ImageManager.IImage image = i < count ? images.getImageAt(i) : null; + if (image == null) { + break; + } + Bitmap temp = image.miniThumbBitmap(); + if (temp != null) { + Bitmap temp2 = ImageLoader.transform(m, temp, imageWidth, imageHeight, true); + if (temp2 != temp) + temp.recycle(); + temp = temp2; + } + + 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); + + mFlipItem = MenuHelper.addFlipOrientation(menu, this, mPrefs); + + menu.add(0, 0, 0, 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; + } + + @Override + public boolean onPrepareOptionsMenu(android.view.Menu menu) { + int keyboard = getResources().getConfiguration().keyboardHidden; + mFlipItem.setEnabled(keyboard == android.content.res.Configuration.KEYBOARDHIDDEN_YES); + + return true; + } +} |