diff options
author | Owen Lin <owenlin@google.com> | 2009-10-26 00:18:07 -0700 |
---|---|---|
committer | Owen Lin <owenlin@google.com> | 2009-10-29 21:44:06 -0700 |
commit | 79bc8acc67097c09907a71c4a5a72ab85eb58087 (patch) | |
tree | 568523f07085f8c8ad3839db5d3219d159919f2b | |
parent | edafa3e7334aac23c7507afdeeb7c849d95b9d70 (diff) | |
download | LegacyCamera-79bc8acc67097c09907a71c4a5a72ab85eb58087.tar.gz LegacyCamera-79bc8acc67097c09907a71c4a5a72ab85eb58087.tar.bz2 LegacyCamera-79bc8acc67097c09907a71c4a5a72ab85eb58087.zip |
Remove unused code in Camera app.
Change-Id: I7b25fde19a172b6910d0217581cf61152d494a82
31 files changed, 127 insertions, 5974 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index efbaa3dc..ec72fb77 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -58,21 +58,6 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> - <activity android:name="GalleryPicker" android:label="@string/gallery_picker_label" - android:configChanges="orientation|keyboardHidden" - android:icon="@drawable/ic_launcher_gallery" - android:clearTaskOnLaunch="true" - android:taskAffinity="android.task.pictures"> - </activity> - <activity android:name="ImageGallery" android:label="@string/gallery_label" - android:configChanges="orientation|keyboardHidden" - android:icon="@drawable/ic_launcher_gallery"> - </activity> - <activity android:name="CropImage" - android:process=":CropImage" - android:configChanges="orientation|keyboardHidden" - android:label="@string/crop_label"> - </activity> <activity android:name="ReviewImage" android:label="@string/view_label" android:theme="@style/CustomTheme" @@ -80,46 +65,6 @@ android:configChanges="orientation|keyboardHidden" android:exported="true"> </activity> - <activity android:name="ViewImage" - android:label="@string/view_label" - android:screenOrientation="behind" - android:configChanges="orientation|keyboardHidden"> - </activity> - <activity android:name="MovieView" - android:label="@string/movieviewlabel" - android:screenOrientation="landscape" - android:configChanges="orientation|keyboardHidden" - android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> - </activity> - <activity android:name=".DeleteImage" - android:label="@string/delete_images_message" - android:theme="@style/Theme.DeleteImageDialog"> - </activity> - - <activity android:name="GallerySettings" android:label="@string/preferences_label"> - </activity> - - <activity android:name=".Wallpaper" - android:label="@string/camera_setas_wallpaper" - android:icon="@drawable/ic_launcher_gallery"> - </activity> - - <activity android:name=".PickWallpaper" - android:label="@string/camera_pick_wallpaper" - android:icon="@drawable/ic_launcher_gallery"> - </activity> - - <!-- We configure a widget by asking to pick a photo, then crop it, and store the config internally --> - <activity android:name="PhotoAppWidgetConfigure"> - </activity> - - <!-- We also allow direct binding where the caller provides a bitmap and - appWidgetId to bind. We require the permission because this changes our - internal database without user confirmation. --> - <activity android:name="PhotoAppWidgetBind" android:exported="true" - android:theme="@android:style/Theme.NoDisplay" - android:permission="android.permission.BIND_APPWIDGET" /> - </application> </manifest> diff --git a/src/com/android/camera/BitmapCache.java b/src/com/android/camera/BitmapCache.java new file mode 100644 index 00000000..3476c71f --- /dev/null +++ b/src/com/android/camera/BitmapCache.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2009 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.graphics.Bitmap; + +class BitmapCache implements ImageViewTouchBase.Recycler { + public static class Entry { + int mPos; + Bitmap mBitmap; + public Entry() { + clear(); + } + public void clear() { + mPos = -1; + mBitmap = null; + } + } + + private final Entry[] mCache; + + public BitmapCache(int size) { + mCache = new Entry[size]; + for (int i = 0; i < mCache.length; i++) { + mCache[i] = new Entry(); + } + } + + // Given the position, find the associated entry. Returns null if there is + // no such entry. + private Entry findEntry(int pos) { + for (Entry e : mCache) { + if (pos == e.mPos) { + return e; + } + } + return null; + } + + // Returns the thumb bitmap if we have it, otherwise return null. + public synchronized Bitmap getBitmap(int pos) { + Entry e = findEntry(pos); + if (e != null) { + return e.mBitmap; + } + return null; + } + + public synchronized void put(int pos, Bitmap bitmap) { + // First see if we already have this entry. + if (findEntry(pos) != null) { + return; + } + + // Find the best entry we should replace. + // See if there is any empty entry. + // Otherwise assuming sequential access, kick out the entry with the + // greatest distance. + Entry best = null; + int maxDist = -1; + for (Entry e : mCache) { + if (e.mPos == -1) { + best = e; + break; + } else { + int dist = Math.abs(pos - e.mPos); + if (dist > maxDist) { + maxDist = dist; + best = e; + } + } + } + + // Recycle the image being kicked out. + // This only works because our current usage is sequential, so we + // do not happen to recycle the image being displayed. + if (best.mBitmap != null) { + best.mBitmap.recycle(); + } + + best.mPos = pos; + best.mBitmap = bitmap; + } + + // Recycle all bitmaps in the cache and clear the cache. + public synchronized void clear() { + for (Entry e : mCache) { + if (e.mBitmap != null) { + e.mBitmap.recycle(); + } + e.clear(); + } + } + + // Returns whether the bitmap is in the cache. + public synchronized boolean hasBitmap(int pos) { + Entry e = findEntry(pos); + return (e != null); + } + + // Recycle the bitmap if it's not in the cache. + // The input must be non-null. + public synchronized void recycle(Bitmap b) { + for (Entry e : mCache) { + if (e.mPos != -1) { + if (e.mBitmap == b) { + return; + } + } + } + b.recycle(); + } +} diff --git a/src/com/android/camera/DeleteImage.java b/src/com/android/camera/DeleteImage.java deleted file mode 100644 index dec65ee2..00000000 --- a/src/com/android/camera/DeleteImage.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2009 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.content.ContentResolver; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.widget.ProgressBar; - -import java.util.ArrayList; - -public class DeleteImage extends NoSearchActivity { - - @SuppressWarnings("unused") - private static final String TAG = "DeleteImage"; - private ProgressBar mProgressBar; - private ArrayList<Uri> mUriList; // a list of image uri - private int mIndex = 0; // next image to delete - private final Handler mHandler = new Handler(); - private final Runnable mDeleteNextRunnable = new Runnable() { - public void run() { - deleteNext(); - } - }; - private ContentResolver mContentResolver; - private boolean mPausing; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Intent intent = getIntent(); - mUriList = intent.getParcelableArrayListExtra("delete-uris"); - if (mUriList == null) { - finish(); - } - setContentView(R.layout.delete_image); - mProgressBar = (ProgressBar) findViewById(R.id.delete_progress); - mContentResolver = getContentResolver(); - } - - @Override - protected void onResume() { - super.onResume(); - mPausing = false; - mHandler.post(mDeleteNextRunnable); - } - - private void deleteNext() { - if (mPausing) return; - if (mIndex >= mUriList.size()) { - finish(); - return; - } - Uri uri = mUriList.get(mIndex++); - // The max progress value of the bar is set to 10000 in the xml file. - mProgressBar.setProgress(mIndex * 10000 / mUriList.size()); - mContentResolver.delete(uri, null, null); - mHandler.post(mDeleteNextRunnable); - } - - @Override - protected void onPause() { - super.onPause(); - mPausing = true; - } -} diff --git a/src/com/android/camera/DrmWallpaper.java b/src/com/android/camera/DrmWallpaper.java deleted file mode 100644 index 643b8769..00000000 --- a/src/com/android/camera/DrmWallpaper.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.content.Intent; - -/** - * Wallpaper picker for DRM images. This just redirects to the standard pick - * action. - */ -public class DrmWallpaper extends Wallpaper { - - @Override - protected void formatIntent(Intent intent) { - super.formatIntent(intent); - intent.putExtra("pick-drm", true); - } -} diff --git a/src/com/android/camera/GalleryPicker.java b/src/com/android/camera/GalleryPicker.java deleted file mode 100644 index 1a6db37d..00000000 --- a/src/com/android/camera/GalleryPicker.java +++ /dev/null @@ -1,941 +0,0 @@ -/* - * 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.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; - } -} diff --git a/src/com/android/camera/GalleryPickerItem.java b/src/com/android/camera/GalleryPickerItem.java deleted file mode 100644 index 99e4a586..00000000 --- a/src/com/android/camera/GalleryPickerItem.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2008 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.content.Context; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.widget.ImageView; - -class GalleryPickerItem extends ImageView { - private Drawable mFrame; - private Rect mFrameBounds = new Rect(); - private Drawable mOverlay; - - public GalleryPickerItem(Context context) { - this(context, null); - } - - public GalleryPickerItem(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public GalleryPickerItem(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - - mFrame = getResources().getDrawable(R.drawable.frame_gallery_preview); - mFrame.setCallback(this); - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || (who == mFrame) - || (who == mOverlay); - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - if (mFrame != null) { - int[] drawableState = getDrawableState(); - mFrame.setState(drawableState); - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - final Rect frameBounds = mFrameBounds; - if (frameBounds.isEmpty()) { - final int w = getWidth(); - final int h = getHeight(); - - frameBounds.set(0, 0, w, h); - mFrame.setBounds(frameBounds); - if (mOverlay != null) { - mOverlay.setBounds(w - mOverlay.getIntrinsicWidth(), - h - mOverlay.getIntrinsicHeight(), w, h); - } - } - - mFrame.draw(canvas); - if (mOverlay != null) { - mOverlay.draw(canvas); - } - } - - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - mFrameBounds.setEmpty(); - } - - public void setOverlay(int overlayId) { - if (overlayId >= 0) { - mOverlay = getResources().getDrawable(overlayId); - mFrameBounds.setEmpty(); - } else { - mOverlay = null; - } - } -} diff --git a/src/com/android/camera/GallerySettings.java b/src/com/android/camera/GallerySettings.java deleted file mode 100644 index 32c806c1..00000000 --- a/src/com/android/camera/GallerySettings.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.os.Bundle; -import android.preference.PreferenceActivity; - -// GallerySettings -// -// This is the setting screen for Gallery. -// It reads the available settings from an XML resource. -public class GallerySettings extends PreferenceActivity { - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.gallery_preferences); - } -} diff --git a/src/com/android/camera/GridViewSpecial.java b/src/com/android/camera/GridViewSpecial.java deleted file mode 100644 index 5326ebb6..00000000 --- a/src/com/android/camera/GridViewSpecial.java +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * Copyright (C) 2009 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 static com.android.camera.Util.Assert; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.os.Handler; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.GestureDetector.SimpleOnGestureListener; -import android.widget.Scroller; - -import com.android.camera.gallery.IImage; -import com.android.camera.gallery.IImageList; - -import java.util.HashMap; - -class GridViewSpecial extends View { - @SuppressWarnings("unused") - private static final String TAG = "GridViewSpecial"; - private static final float MAX_FLING_VELOCITY = 2500; - - public static interface Listener { - public void onImageClicked(int index); - public void onImageTapped(int index); - public void onLayoutComplete(boolean changed); - - /** - * Invoked when the <code>GridViewSpecial</code> scrolls. - * - * @param scrollPosition the position of the scroller in the range - * [0, 1], when 0 means on the top and 1 means on the buttom - */ - public void onScroll(float scrollPosition); - } - - public static interface DrawAdapter { - public void drawImage(Canvas canvas, IImage image, - Bitmap b, int xPos, int yPos, int w, int h); - public void drawDecoration(Canvas canvas, IImage image, - int xPos, int yPos, int w, int h); - public boolean needsDecoration(); - } - - public static final int INDEX_NONE = -1; - - // There are two cell size we will use. It can be set by setSizeChoice(). - // The mLeftEdgePadding fields is filled in onLayout(). See the comments - // in onLayout() for details. - static class LayoutSpec { - LayoutSpec(int w, int h, int intercellSpacing, int leftEdgePadding, - DisplayMetrics metrics) { - mCellWidth = dpToPx(w, metrics); - mCellHeight = dpToPx(h, metrics); - mCellSpacing = dpToPx(intercellSpacing, metrics); - mLeftEdgePadding = dpToPx(leftEdgePadding, metrics); - } - int mCellWidth, mCellHeight; - int mCellSpacing; - int mLeftEdgePadding; - } - - private LayoutSpec [] mCellSizeChoices; - - private void initCellSize() { - Activity a = (Activity) getContext(); - DisplayMetrics metrics = new DisplayMetrics(); - a.getWindowManager().getDefaultDisplay().getMetrics(metrics); - mCellSizeChoices = new LayoutSpec[] { - new LayoutSpec(67, 67, 8, 0, metrics), - new LayoutSpec(92, 92, 8, 0, metrics), - }; - } - - // Converts dp to pixel. - private static int dpToPx(int dp, DisplayMetrics metrics) { - return (int) (metrics.density * dp); - } - - // These are set in init(). - private final Handler mHandler = new Handler(); - private GestureDetector mGestureDetector; - private ImageBlockManager mImageBlockManager; - - // These are set in set*() functions. - private ImageLoader mLoader; - private Listener mListener = null; - private DrawAdapter mDrawAdapter = null; - private IImageList mAllImages = ImageManager.makeEmptyImageList(); - private int mSizeChoice = 1; // default is big cell size - - // These are set in onLayout(). - private LayoutSpec mSpec; - private int mColumns; - private int mMaxScrollY; - - // We can handle events only if onLayout() is completed. - private boolean mLayoutComplete = false; - - // Selection state - private int mCurrentSelection = INDEX_NONE; - private int mCurrentPressState = 0; - private static final int TAPPING_FLAG = 1; - private static final int CLICKING_FLAG = 2; - - // These are cached derived information. - private int mCount; // Cache mImageList.getCount(); - private int mRows; // Cache (mCount + mColumns - 1) / mColumns - private int mBlockHeight; // Cache mSpec.mCellSpacing + mSpec.mCellHeight - - private boolean mRunning = false; - private Scroller mScroller = null; - - public GridViewSpecial(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - private void init(Context context) { - setVerticalScrollBarEnabled(true); - initializeScrollbars(context.obtainStyledAttributes( - android.R.styleable.View)); - mGestureDetector = new GestureDetector(context, - new MyGestureDetector()); - setFocusableInTouchMode(true); - initCellSize(); - } - - private final Runnable mRedrawCallback = new Runnable() { - public void run() { - invalidate(); - } - }; - - public void setLoader(ImageLoader loader) { - Assert(mRunning == false); - mLoader = loader; - } - - public void setListener(Listener listener) { - Assert(mRunning == false); - mListener = listener; - } - - public void setDrawAdapter(DrawAdapter adapter) { - Assert(mRunning == false); - mDrawAdapter = adapter; - } - - public void setImageList(IImageList list) { - Assert(mRunning == false); - mAllImages = list; - mCount = mAllImages.getCount(); - } - - public void setSizeChoice(int choice) { - Assert(mRunning == false); - if (mSizeChoice == choice) return; - mSizeChoice = choice; - } - - @Override - public void onLayout(boolean changed, int left, int top, - int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (!mRunning) { - return; - } - - mSpec = mCellSizeChoices[mSizeChoice]; - - int width = right - left; - - // The width is divided into following parts: - // - // LeftEdgePadding CellWidth (CellSpacing CellWidth)* RightEdgePadding - // - // We determine number of cells (columns) first, then the left and right - // padding are derived. We make left and right paddings the same size. - // - // The height is divided into following parts: - // - // CellSpacing (CellHeight CellSpacing)+ - - mColumns = 1 + (width - mSpec.mCellWidth) - / (mSpec.mCellWidth + mSpec.mCellSpacing); - - mSpec.mLeftEdgePadding = (width - - ((mColumns - 1) * mSpec.mCellSpacing) - - (mColumns * mSpec.mCellWidth)) / 2; - - mRows = (mCount + mColumns - 1) / mColumns; - mBlockHeight = mSpec.mCellSpacing + mSpec.mCellHeight; - mMaxScrollY = mSpec.mCellSpacing + (mRows * mBlockHeight) - - (bottom - top); - - // Put mScrollY in the valid range. This matters if mMaxScrollY is - // changed. For example, orientation changed from portrait to landscape. - mScrollY = Math.max(0, Math.min(mMaxScrollY, mScrollY)); - - generateOutlineBitmap(); - - if (mImageBlockManager != null) { - mImageBlockManager.recycle(); - } - - mImageBlockManager = new ImageBlockManager(mHandler, mRedrawCallback, - mAllImages, mLoader, mDrawAdapter, mSpec, mColumns, width, - mOutline[OUTLINE_EMPTY]); - - mListener.onLayoutComplete(changed); - - moveDataWindow(); - - mLayoutComplete = true; - } - - @Override - protected int computeVerticalScrollRange() { - return mMaxScrollY + getHeight(); - } - - // We cache the three outlines from NinePatch to Bitmap to speed up - // drawing. The cache must be updated if the cell size is changed. - public static final int OUTLINE_EMPTY = 0; - public static final int OUTLINE_PRESSED = 1; - public static final int OUTLINE_SELECTED = 2; - - public Bitmap mOutline[] = new Bitmap[3]; - - private void generateOutlineBitmap() { - int w = mSpec.mCellWidth; - int h = mSpec.mCellHeight; - - for (int i = 0; i < mOutline.length; i++) { - mOutline[i] = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - } - - Drawable cellOutline; - cellOutline = GridViewSpecial.this.getResources() - .getDrawable(android.R.drawable.gallery_thumb); - cellOutline.setBounds(0, 0, w, h); - Canvas canvas = new Canvas(); - - canvas.setBitmap(mOutline[OUTLINE_EMPTY]); - cellOutline.setState(EMPTY_STATE_SET); - cellOutline.draw(canvas); - - canvas.setBitmap(mOutline[OUTLINE_PRESSED]); - cellOutline.setState( - PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET); - cellOutline.draw(canvas); - - canvas.setBitmap(mOutline[OUTLINE_SELECTED]); - cellOutline.setState(ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET); - cellOutline.draw(canvas); - } - - private void moveDataWindow() { - // Calculate visible region according to scroll position. - int startRow = (mScrollY - mSpec.mCellSpacing) / mBlockHeight; - int endRow = (mScrollY + getHeight() - mSpec.mCellSpacing - 1) - / mBlockHeight + 1; - - // Limit startRow and endRow to the valid range. - // Make sure we handle the mRows == 0 case right. - startRow = Math.max(Math.min(startRow, mRows - 1), 0); - endRow = Math.max(Math.min(endRow, mRows), 0); - mImageBlockManager.setVisibleRows(startRow, endRow); - } - - // In MyGestureDetector we have to check canHandleEvent() because - // GestureDetector could queue events and fire them later. At that time - // stop() may have already been called and we can't handle the events. - private class MyGestureDetector extends SimpleOnGestureListener { - private AudioManager mAudioManager; - - @Override - public boolean onDown(MotionEvent e) { - if (!canHandleEvent()) return false; - if (mScroller != null && !mScroller.isFinished()) { - mScroller.forceFinished(true); - return false; - } - int index = computeSelectedIndex(e.getX(), e.getY()); - if (index >= 0 && index < mCount) { - setSelectedIndex(index); - } else { - setSelectedIndex(INDEX_NONE); - } - return true; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, - float velocityX, float velocityY) { - if (!canHandleEvent()) return false; - if (velocityY > MAX_FLING_VELOCITY) { - velocityY = MAX_FLING_VELOCITY; - } else if (velocityY < -MAX_FLING_VELOCITY) { - velocityY = -MAX_FLING_VELOCITY; - } - - setSelectedIndex(INDEX_NONE); - mScroller = new Scroller(getContext()); - mScroller.fling(0, mScrollY, 0, -(int) velocityY, 0, 0, 0, - mMaxScrollY); - computeScroll(); - - return true; - } - - @Override - public void onLongPress(MotionEvent e) { - if (!canHandleEvent()) return; - performLongClick(); - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - if (!canHandleEvent()) return false; - setSelectedIndex(INDEX_NONE); - scrollBy(0, (int) distanceY); - invalidate(); - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (!canHandleEvent()) return false; - int index = computeSelectedIndex(e.getX(), e.getY()); - if (index >= 0 && index < mCount) { - // Play click sound. - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext() - .getSystemService(Context.AUDIO_SERVICE); - } - mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); - - mListener.onImageTapped(index); - return true; - } - return false; - } - } - - public int getCurrentSelection() { - return mCurrentSelection; - } - - public void invalidateImage(int index) { - if (index != INDEX_NONE) { - mImageBlockManager.invalidateImage(index); - } - } - - /** - * - * @param index <code>INDEX_NONE</code> (-1) means remove selection. - */ - public void setSelectedIndex(int index) { - // A selection box will be shown for the image that being selected, - // (by finger or by the dpad center key). The selection box can be drawn - // in two colors. One color (yellow) is used when the the image is - // still being tapped or clicked (the finger is still on the touch - // screen or the dpad center key is not released). Another color - // (orange) is used after the finger leaves touch screen or the dpad - // center key is released. - - if (mCurrentSelection == index) { - return; - } - // This happens when the last picture is deleted. - mCurrentSelection = Math.min(index, mCount - 1); - - if (mCurrentSelection != INDEX_NONE) { - ensureVisible(mCurrentSelection); - } - invalidate(); - } - - public void scrollToImage(int index) { - Rect r = getRectForPosition(index); - scrollTo(0, r.top); - } - - public void scrollToVisible(int index) { - Rect r = getRectForPosition(index); - int top = getScrollY(); - int bottom = getScrollY() + getHeight(); - if (r.bottom > bottom) { - scrollTo(0, r.bottom - getHeight()); - } else if (r.top < top) { - scrollTo(0, r.top); - } - } - - private void ensureVisible(int pos) { - Rect r = getRectForPosition(pos); - int top = getScrollY(); - int bot = top + getHeight(); - - if (r.bottom > bot) { - mScroller = new Scroller(getContext()); - mScroller.startScroll(mScrollX, mScrollY, 0, - r.bottom - getHeight() - mScrollY, 200); - computeScroll(); - } else if (r.top < top) { - mScroller = new Scroller(getContext()); - mScroller.startScroll(mScrollX, mScrollY, 0, r.top - mScrollY, 200); - computeScroll(); - } - } - - public void start() { - // These must be set before start(). - Assert(mLoader != null); - Assert(mListener != null); - Assert(mDrawAdapter != null); - mRunning = true; - requestLayout(); - } - - // If the the underlying data is changed, for example, - // an image is deleted, or the size choice is changed, - // The following sequence is needed: - // - // mGvs.stop(); - // mGvs.set...(...); - // mGvs.set...(...); - // mGvs.start(); - public void stop() { - // Remove the long press callback from the queue if we are going to - // stop. - mHandler.removeCallbacks(mLongPressCallback); - mScroller = null; - if (mImageBlockManager != null) { - mImageBlockManager.recycle(); - mImageBlockManager = null; - } - mRunning = false; - mCurrentSelection = INDEX_NONE; - } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (!canHandleEvent()) return; - mImageBlockManager.doDraw(canvas, getWidth(), getHeight(), mScrollY); - paintDecoration(canvas); - paintSelection(canvas); - moveDataWindow(); - } - - @Override - public void computeScroll() { - if (mScroller != null) { - boolean more = mScroller.computeScrollOffset(); - scrollTo(0, mScroller.getCurrY()); - if (more) { - invalidate(); // So we draw again - } else { - mScroller = null; - } - } else { - super.computeScroll(); - } - } - - // Return the rectange for the thumbnail in the given position. - Rect getRectForPosition(int pos) { - int row = pos / mColumns; - int col = pos - (row * mColumns); - - int left = mSpec.mLeftEdgePadding - + (col * (mSpec.mCellWidth + mSpec.mCellSpacing)); - int top = row * mBlockHeight; - - return new Rect(left, top, - left + mSpec.mCellWidth + mSpec.mCellSpacing, - top + mSpec.mCellHeight + mSpec.mCellSpacing); - } - - // Inverse of getRectForPosition: from screen coordinate to image position. - int computeSelectedIndex(float xFloat, float yFloat) { - int x = (int) xFloat; - int y = (int) yFloat; - - int spacing = mSpec.mCellSpacing; - int leftSpacing = mSpec.mLeftEdgePadding; - - int row = (mScrollY + y - spacing) / (mSpec.mCellHeight + spacing); - int col = Math.min(mColumns - 1, - (x - leftSpacing) / (mSpec.mCellWidth + spacing)); - return (row * mColumns) + col; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (!canHandleEvent()) { - return false; - } - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - mCurrentPressState |= TAPPING_FLAG; - invalidate(); - break; - case MotionEvent.ACTION_UP: - mCurrentPressState &= ~TAPPING_FLAG; - invalidate(); - break; - } - mGestureDetector.onTouchEvent(ev); - // Consume all events - return true; - } - - @Override - public void scrollBy(int x, int y) { - scrollTo(mScrollX + x, mScrollY + y); - } - - public void scrollTo(float scrollPosition) { - scrollTo(0, Math.round(scrollPosition * mMaxScrollY)); - } - - @Override - public void scrollTo(int x, int y) { - y = Math.max(0, Math.min(mMaxScrollY, y)); - if (mSpec != null) { - mListener.onScroll((float) mScrollY / mMaxScrollY); - } - super.scrollTo(x, y); - } - - private boolean canHandleEvent() { - return mRunning && mLayoutComplete; - } - - private final Runnable mLongPressCallback = new Runnable() { - public void run() { - mCurrentPressState &= ~CLICKING_FLAG; - showContextMenu(); - } - }; - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (!canHandleEvent()) return false; - int sel = mCurrentSelection; - if (sel != INDEX_NONE) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (sel != mCount - 1 && (sel % mColumns < mColumns - 1)) { - sel += 1; - } - break; - case KeyEvent.KEYCODE_DPAD_LEFT: - if (sel > 0 && (sel % mColumns != 0)) { - sel -= 1; - } - break; - case KeyEvent.KEYCODE_DPAD_UP: - if (sel >= mColumns) { - sel -= mColumns; - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - sel = Math.min(mCount - 1, sel + mColumns); - break; - case KeyEvent.KEYCODE_DPAD_CENTER: - if (event.getRepeatCount() == 0) { - mCurrentPressState |= CLICKING_FLAG; - mHandler.postDelayed(mLongPressCallback, - ViewConfiguration.getLongPressTimeout()); - } - break; - default: - return super.onKeyDown(keyCode, event); - } - } else { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - int startRow = - (mScrollY - mSpec.mCellSpacing) / mBlockHeight; - int topPos = startRow * mColumns; - Rect r = getRectForPosition(topPos); - if (r.top < getScrollY()) { - topPos += mColumns; - } - topPos = Math.min(mCount - 1, topPos); - sel = topPos; - break; - default: - return super.onKeyDown(keyCode, event); - } - } - setSelectedIndex(sel); - return true; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (!canHandleEvent()) return false; - - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { - mCurrentPressState &= ~CLICKING_FLAG; - invalidate(); - - // The keyUp doesn't get called when the longpress menu comes up. We - // only get here when the user lets go of the center key before the - // longpress menu comes up. - mHandler.removeCallbacks(mLongPressCallback); - - // open the photo - mListener.onImageClicked(mCurrentSelection); - return true; - } - return super.onKeyUp(keyCode, event); - } - - private void paintDecoration(Canvas canvas) { - if (!mDrawAdapter.needsDecoration()) return; - - // Calculate visible region according to scroll position. - int startRow = (mScrollY - mSpec.mCellSpacing) / mBlockHeight; - int endRow = (mScrollY + getHeight() - mSpec.mCellSpacing - 1) - / mBlockHeight + 1; - - // Limit startRow and endRow to the valid range. - // Make sure we handle the mRows == 0 case right. - startRow = Math.max(Math.min(startRow, mRows - 1), 0); - endRow = Math.max(Math.min(endRow, mRows), 0); - - int startIndex = startRow * mColumns; - int endIndex = Math.min(endRow * mColumns, mCount); - - int xPos = mSpec.mLeftEdgePadding; - int yPos = mSpec.mCellSpacing + startRow * mBlockHeight; - int off = 0; - for (int i = startIndex; i < endIndex; i++) { - IImage image = mAllImages.getImageAt(i); - - mDrawAdapter.drawDecoration(canvas, image, xPos, yPos, - mSpec.mCellWidth, mSpec.mCellHeight); - - // Calculate next position - off += 1; - if (off == mColumns) { - xPos = mSpec.mLeftEdgePadding; - yPos += mBlockHeight; - off = 0; - } else { - xPos += mSpec.mCellWidth + mSpec.mCellSpacing; - } - } - } - - private void paintSelection(Canvas canvas) { - if (mCurrentSelection == INDEX_NONE) return; - - int row = mCurrentSelection / mColumns; - int col = mCurrentSelection - (row * mColumns); - - int spacing = mSpec.mCellSpacing; - int leftSpacing = mSpec.mLeftEdgePadding; - int xPos = leftSpacing + (col * (mSpec.mCellWidth + spacing)); - int yTop = spacing + (row * mBlockHeight); - - int type = OUTLINE_SELECTED; - if (mCurrentPressState != 0) { - type = OUTLINE_PRESSED; - } - canvas.drawBitmap(mOutline[type], xPos, yTop, null); - } -} - -class ImageBlockManager { - @SuppressWarnings("unused") - private static final String TAG = "ImageBlockManager"; - - // Number of rows we want to cache. - // Assume there are 6 rows per page, this caches 5 pages. - private static final int CACHE_ROWS = 30; - - // mCache maps from row number to the ImageBlock. - private final HashMap<Integer, ImageBlock> mCache; - - // These are parameters set in the constructor. - private final Handler mHandler; - private final Runnable mRedrawCallback; // Called after a row is loaded, - // so GridViewSpecial can draw - // again using the new images. - private final IImageList mImageList; - private final ImageLoader mLoader; - private final GridViewSpecial.DrawAdapter mDrawAdapter; - private final GridViewSpecial.LayoutSpec mSpec; - private final int mColumns; // Columns per row. - private final int mBlockWidth; // The width of an ImageBlock. - private final Bitmap mOutline; // The outline bitmap put on top of each - // image. - private final int mCount; // Cache mImageList.getCount(). - private final int mRows; // Cache (mCount + mColumns - 1) / mColumns - private final int mBlockHeight; // The height of an ImageBlock. - - // Visible row range: [mStartRow, mEndRow). Set by setVisibleRows(). - private int mStartRow = 0; - private int mEndRow = 0; - - ImageBlockManager(Handler handler, Runnable redrawCallback, - IImageList imageList, ImageLoader loader, - GridViewSpecial.DrawAdapter adapter, - GridViewSpecial.LayoutSpec spec, - int columns, int blockWidth, Bitmap outline) { - mHandler = handler; - mRedrawCallback = redrawCallback; - mImageList = imageList; - mLoader = loader; - mDrawAdapter = adapter; - mSpec = spec; - mColumns = columns; - mBlockWidth = blockWidth; - mOutline = outline; - mBlockHeight = mSpec.mCellSpacing + mSpec.mCellHeight; - mCount = imageList.getCount(); - mRows = (mCount + mColumns - 1) / mColumns; - mCache = new HashMap<Integer, ImageBlock>(); - mPendingRequest = 0; - initGraphics(); - } - - // Set the window of visible rows. Once set we will start to load them as - // soon as possible (if they are not already in cache). - public void setVisibleRows(int startRow, int endRow) { - if (startRow != mStartRow || endRow != mEndRow) { - mStartRow = startRow; - mEndRow = endRow; - startLoading(); - } - } - - int mPendingRequest; // Number of pending requests (sent to ImageLoader). - // We want to keep enough requests in ImageLoader's queue, but not too - // many. - static final int REQUESTS_LOW = 3; - static final int REQUESTS_HIGH = 6; - - // After clear requests currently in queue, start loading the thumbnails. - // We need to clear the queue first because the proper order of loading - // may have changed (because the visible region changed, or some images - // have been invalidated). - private void startLoading() { - clearLoaderQueue(); - continueLoading(); - } - - private void clearLoaderQueue() { - int[] tags = mLoader.clearQueue(); - for (int pos : tags) { - int row = pos / mColumns; - int col = pos - row * mColumns; - ImageBlock blk = mCache.get(row); - Assert(blk != null); // We won't reuse the block if it has pending - // requests. See getEmptyBlock(). - blk.cancelRequest(col); - } - } - - // Scan the cache and send requests to ImageLoader if needed. - private void continueLoading() { - // Check if we still have enough requests in the queue. - if (mPendingRequest >= REQUESTS_LOW) return; - - // Scan the visible rows. - for (int i = mStartRow; i < mEndRow; i++) { - if (scanOne(i)) return; - } - - int range = (CACHE_ROWS - (mEndRow - mStartRow)) / 2; - // Scan other rows. - // d is the distance between the row and visible region. - for (int d = 1; d <= range; d++) { - int after = mEndRow - 1 + d; - int before = mStartRow - d; - if (after >= mRows && before < 0) { - break; // Nothing more the scan. - } - if (after < mRows && scanOne(after)) return; - if (before >= 0 && scanOne(before)) return; - } - } - - // Returns true if we can stop scanning. - private boolean scanOne(int i) { - mPendingRequest += tryToLoad(i); - return mPendingRequest >= REQUESTS_HIGH; - } - - // Returns number of requests we issued for this row. - private int tryToLoad(int row) { - Assert(row >= 0 && row < mRows); - ImageBlock blk = mCache.get(row); - if (blk == null) { - // Find an empty block - blk = getEmptyBlock(); - blk.setRow(row); - blk.invalidate(); - mCache.put(row, blk); - } - return blk.loadImages(); - } - - // Get an empty block for the cache. - private ImageBlock getEmptyBlock() { - // See if we can allocate a new block. - if (mCache.size() < CACHE_ROWS) { - return new ImageBlock(); - } - // Reclaim the old block with largest distance from the visible region. - int bestDistance = -1; - int bestIndex = -1; - for (int index : mCache.keySet()) { - // Make sure we don't reclaim a block which still has pending - // request. - if (mCache.get(index).hasPendingRequests()) { - continue; - } - int dist = 0; - if (index >= mEndRow) { - dist = index - mEndRow + 1; - } else if (index < mStartRow) { - dist = mStartRow - index; - } else { - // Inside the visible region. - continue; - } - if (dist > bestDistance) { - bestDistance = dist; - bestIndex = index; - } - } - return mCache.remove(bestIndex); - } - - public void invalidateImage(int index) { - int row = index / mColumns; - int col = index - (row * mColumns); - ImageBlock blk = mCache.get(row); - if (blk == null) return; - if ((blk.mCompletedMask & (1 << col)) != 0) { - blk.mCompletedMask &= ~(1 << col); - } - startLoading(); - } - - // After calling recycle(), the instance should not be used anymore. - public void recycle() { - for (ImageBlock blk : mCache.values()) { - blk.recycle(); - } - mCache.clear(); - mEmptyBitmap.recycle(); - } - - // Draw the images to the given canvas. - public void doDraw(Canvas canvas, int thisWidth, int thisHeight, - int scrollPos) { - final int height = mBlockHeight; - - // Note that currentBlock could be negative. - int currentBlock = (scrollPos < 0) - ? ((scrollPos - height + 1) / height) - : (scrollPos / height); - - while (true) { - final int yPos = currentBlock * height; - if (yPos >= scrollPos + thisHeight) { - break; - } - - ImageBlock blk = mCache.get(currentBlock); - if (blk != null) { - blk.doDraw(canvas, 0, yPos); - } else { - drawEmptyBlock(canvas, 0, yPos, currentBlock); - } - - currentBlock += 1; - } - } - - // Return number of columns in the given row. (This could be less than - // mColumns for the last row). - private int numColumns(int row) { - return Math.min(mColumns, mCount - row * mColumns); - } - - // Draw a block which has not been loaded. - private void drawEmptyBlock(Canvas canvas, int xPos, int yPos, int row) { - // Draw the background. - canvas.drawRect(xPos, yPos, xPos + mBlockWidth, yPos + mBlockHeight, - mBackgroundPaint); - - // Draw the empty images. - int x = xPos + mSpec.mLeftEdgePadding; - int y = yPos + mSpec.mCellSpacing; - int cols = numColumns(row); - - for (int i = 0; i < cols; i++) { - canvas.drawBitmap(mEmptyBitmap, x, y, null); - x += (mSpec.mCellWidth + mSpec.mCellSpacing); - } - } - - // mEmptyBitmap is what we draw if we the wanted block hasn't been loaded. - // (If the user scrolls too fast). It is a gray image with normal outline. - // mBackgroundPaint is used to draw the (black) background outside - // mEmptyBitmap. - Paint mBackgroundPaint; - private Bitmap mEmptyBitmap; - - private void initGraphics() { - mBackgroundPaint = new Paint(); - mBackgroundPaint.setStyle(Paint.Style.FILL); - mBackgroundPaint.setColor(0xFF000000); // black - mEmptyBitmap = Bitmap.createBitmap(mSpec.mCellWidth, mSpec.mCellHeight, - Bitmap.Config.RGB_565); - Canvas canvas = new Canvas(mEmptyBitmap); - canvas.drawRGB(0xDD, 0xDD, 0xDD); - canvas.drawBitmap(mOutline, 0, 0, null); - } - - // ImageBlock stores bitmap for one row. The loaded thumbnail images are - // drawn to mBitmap. mBitmap is later used in onDraw() of GridViewSpecial. - private class ImageBlock { - private Bitmap mBitmap; - private final Canvas mCanvas; - - // Columns which have been requested to the loader - private int mRequestedMask; - - // Columns which have been completed from the loader - private int mCompletedMask; - - // The row number this block represents. - private int mRow; - - public ImageBlock() { - mBitmap = Bitmap.createBitmap(mBlockWidth, mBlockHeight, - Bitmap.Config.RGB_565); - mCanvas = new Canvas(mBitmap); - mRow = -1; - } - - public void setRow(int row) { - mRow = row; - } - - public void invalidate() { - // We do not change mRequestedMask or do cancelAllRequests() - // because the data coming from pending requests are valid. (We only - // invalidate data which has been drawn to the bitmap). - mCompletedMask = 0; - } - - // After recycle, the ImageBlock instance should not be accessed. - public void recycle() { - cancelAllRequests(); - mBitmap.recycle(); - mBitmap = null; - } - - private boolean isVisible() { - return mRow >= mStartRow && mRow < mEndRow; - } - - // Returns number of requests submitted to ImageLoader. - public int loadImages() { - Assert(mRow != -1); - - int columns = numColumns(mRow); - - // Calculate what we need. - int needMask = ((1 << columns) - 1) - & ~(mCompletedMask | mRequestedMask); - - if (needMask == 0) { - return 0; - } - - int retVal = 0; - int base = mRow * mColumns; - - for (int col = 0; col < columns; col++) { - if ((needMask & (1 << col)) == 0) { - continue; - } - - int pos = base + col; - - final IImage image = mImageList.getImageAt(pos); - if (image != null) { - // This callback is passed to ImageLoader. It will invoke - // loadImageDone() in the main thread. We limit the callback - // thread to be in this very short function. All other - // processing is done in the main thread. - final int colFinal = col; - ImageLoader.LoadedCallback cb = - new ImageLoader.LoadedCallback() { - public void run(final Bitmap b) { - mHandler.post(new Runnable() { - public void run() { - loadImageDone(image, b, - colFinal); - } - }); - } - }; - // Load Image - mLoader.getBitmap(image, cb, pos); - mRequestedMask |= (1 << col); - retVal += 1; - } - } - - return retVal; - } - - // Whether this block has pending requests. - public boolean hasPendingRequests() { - return mRequestedMask != 0; - } - - // Called when an image is loaded. - private void loadImageDone(IImage image, Bitmap b, - int col) { - if (mBitmap == null) return; // This block has been recycled. - - int spacing = mSpec.mCellSpacing; - int leftSpacing = mSpec.mLeftEdgePadding; - final int yPos = spacing; - final int xPos = leftSpacing - + (col * (mSpec.mCellWidth + spacing)); - - drawBitmap(image, b, xPos, yPos); - - if (b != null) { - b.recycle(); - } - - int mask = (1 << col); - Assert((mCompletedMask & mask) == 0); - Assert((mRequestedMask & mask) != 0); - mRequestedMask &= ~mask; - mCompletedMask |= mask; - mPendingRequest--; - - if (isVisible()) { - mRedrawCallback.run(); - } - - // Kick start next block loading. - continueLoading(); - } - - // Draw the loaded bitmap to the block bitmap. - private void drawBitmap( - IImage image, Bitmap b, int xPos, int yPos) { - mDrawAdapter.drawImage(mCanvas, image, b, xPos, yPos, - mSpec.mCellWidth, mSpec.mCellHeight); - mCanvas.drawBitmap(mOutline, xPos, yPos, null); - } - - // Draw the block bitmap to the specified canvas. - public void doDraw(Canvas canvas, int xPos, int yPos) { - int cols = numColumns(mRow); - - if (cols == mColumns) { - canvas.drawBitmap(mBitmap, xPos, yPos, null); - } else { - - // This must be the last row -- we draw only part of the block. - // Draw the background. - canvas.drawRect(xPos, yPos, xPos + mBlockWidth, - yPos + mBlockHeight, mBackgroundPaint); - // Draw part of the block. - int w = mSpec.mLeftEdgePadding - + cols * (mSpec.mCellWidth + mSpec.mCellSpacing); - Rect srcRect = new Rect(0, 0, w, mBlockHeight); - Rect dstRect = new Rect(srcRect); - dstRect.offset(xPos, yPos); - canvas.drawBitmap(mBitmap, srcRect, dstRect, null); - } - - // Draw the part which has not been loaded. - int isEmpty = ((1 << cols) - 1) & ~mCompletedMask; - - if (isEmpty != 0) { - int x = xPos + mSpec.mLeftEdgePadding; - int y = yPos + mSpec.mCellSpacing; - - for (int i = 0; i < cols; i++) { - if ((isEmpty & (1 << i)) != 0) { - canvas.drawBitmap(mEmptyBitmap, x, y, null); - } - x += (mSpec.mCellWidth + mSpec.mCellSpacing); - } - } - } - - // Mark a request as cancelled. The request has already been removed - // from the queue of ImageLoader, so we only need to mark the fact. - public void cancelRequest(int col) { - int mask = (1 << col); - Assert((mRequestedMask & mask) != 0); - mRequestedMask &= ~mask; - mPendingRequest--; - } - - // Try to cancel all pending requests for this block. After this - // completes there could still be requests not cancelled (because it is - // already in progress). We deal with that situation by setting mBitmap - // to null in recycle() and check this in loadImageDone(). - private void cancelAllRequests() { - for (int i = 0; i < mColumns; i++) { - int mask = (1 << i); - if ((mRequestedMask & mask) != 0) { - int pos = (mRow * mColumns) + i; - if (mLoader.cancel(mImageList.getImageAt(pos))) { - mRequestedMask &= ~mask; - mPendingRequest--; - } - } - } - } - } -} diff --git a/src/com/android/camera/ImageGallery.java b/src/com/android/camera/ImageGallery.java deleted file mode 100644 index 068ac114..00000000 --- a/src/com/android/camera/ImageGallery.java +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * 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.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; -import android.preference.PreferenceManager; -import android.provider.MediaStore; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.view.View.OnClickListener; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -import com.android.camera.gallery.IImage; -import com.android.camera.gallery.IImageList; -import com.android.camera.gallery.VideoObject; - -import java.util.ArrayList; -import java.util.HashSet; - -public class ImageGallery extends NoSearchActivity implements - GridViewSpecial.Listener, GridViewSpecial.DrawAdapter { - private static final String STATE_SCROLL_POSITION = "scroll_position"; - private static final String STATE_SELECTED_INDEX = "first_index"; - - private static final String TAG = "ImageGallery"; - private static final float INVALID_POSITION = -1f; - private ImageManager.ImageListParam mParam; - private IImageList mAllImages; - private int mInclusion; - boolean mSortAscending = false; - private View mNoImagesView; - public static final int CROP_MSG = 2; - - private Dialog mMediaScanningDialog; - private MenuItem mSlideShowItem; - private SharedPreferences mPrefs; - private long mVideoSizeLimit = Long.MAX_VALUE; - private View mFooterOrganizeView; - - private BroadcastReceiver mReceiver = null; - - private final Handler mHandler = new Handler(); - private boolean mLayoutComplete; - private boolean mPausing = true; - private ImageLoader mLoader; - private GridViewSpecial mGvs; - - private Uri mCropResultUri; - - // The index of the first picture in GridViewSpecial. - private int mSelectedIndex = GridViewSpecial.INDEX_NONE; - private float mScrollPosition = INVALID_POSITION; - private boolean mConfigurationChanged = false; - - private HashSet<IImage> mMultiSelected = null; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - - // Must be called before setContentView(). - requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); - - setContentView(R.layout.image_gallery); - - getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, - R.layout.custom_gallery_title); - - mNoImagesView = findViewById(R.id.no_images); - - mGvs = (GridViewSpecial) findViewById(R.id.grid); - mGvs.setListener(this); - - mFooterOrganizeView = findViewById(R.id.footer_organize); - - // consume all click events on the footer view - mFooterOrganizeView.setOnClickListener(Util.getNullOnClickListener()); - initializeFooterButtons(); - - if (isPickIntent()) { - mVideoSizeLimit = getIntent().getLongExtra( - MediaStore.EXTRA_SIZE_LIMIT, Long.MAX_VALUE); - } else { - mVideoSizeLimit = Long.MAX_VALUE; - mGvs.setOnCreateContextMenuListener( - new CreateContextMenuListener()); - } - - setupInclusion(); - - mLoader = new ImageLoader(getContentResolver(), mHandler); - } - - private void initializeFooterButtons() { - Button deleteButton = (Button) findViewById(R.id.button_delete); - deleteButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onDeleteMultipleClicked(); - } - }); - - Button shareButton = (Button) findViewById(R.id.button_share); - shareButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onShareMultipleClicked(); - } - }); - - Button closeButton = (Button) findViewById(R.id.button_close); - closeButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - closeMultiSelectMode(); - } - }); - } - - private MenuItem addSlideShowMenu(Menu menu) { - return menu.add(Menu.NONE, Menu.NONE, MenuHelper.POSITION_SLIDESHOW, - R.string.slide_show) - .setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - return onSlideShowClicked(); - } - }).setIcon(android.R.drawable.ic_menu_slideshow); - } - - public boolean onSlideShowClicked() { - if (!canHandleEvent()) { - return false; - } - IImage img = getCurrentImage(); - if (img == null) { - img = mAllImages.getImageAt(0); - if (img == null) { - return true; - } - } - Uri targetUri = img.fullSizeImageUri(); - Uri thisUri = getIntent().getData(); - if (thisUri != null) { - String bucket = thisUri.getQueryParameter("bucketId"); - if (bucket != null) { - targetUri = targetUri.buildUpon() - .appendQueryParameter("bucketId", bucket) - .build(); - } - } - Intent intent = new Intent(Intent.ACTION_VIEW, targetUri); - intent.putExtra("slideshow", true); - startActivity(intent); - return true; - } - - private final Runnable mDeletePhotoRunnable = new Runnable() { - public void run() { - if (!canHandleEvent()) return; - - IImage currentImage = getCurrentImage(); - - // The selection will be cleared when mGvs.stop() is called, so - // we need to call getCurrentImage() before mGvs.stop(). - mGvs.stop(); - - if (currentImage != null) { - mAllImages.removeImage(currentImage); - } - mGvs.setImageList(mAllImages); - mGvs.start(); - - mNoImagesView.setVisibility(mAllImages.isEmpty() - ? View.VISIBLE - : View.GONE); - } - }; - - private Uri getCurrentImageUri() { - IImage image = getCurrentImage(); - if (image != null) { - return image.fullSizeImageUri(); - } else { - return null; - } - } - - private IImage getCurrentImage() { - int currentSelection = mGvs.getCurrentSelection(); - if (currentSelection < 0 - || currentSelection >= mAllImages.getCount()) { - return null; - } else { - return mAllImages.getImageAt(currentSelection); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mConfigurationChanged = true; - } - - boolean canHandleEvent() { - // Don't process event in pause state. - return (!mPausing) && (mLayoutComplete); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (!canHandleEvent()) return false; - switch (keyCode) { - case KeyEvent.KEYCODE_DEL: - IImage image = getCurrentImage(); - if (image != null) { - MenuHelper.deleteImage( - this, mDeletePhotoRunnable, getCurrentImage()); - } - return true; - } - return super.onKeyDown(keyCode, event); - } - - private boolean isPickIntent() { - String action = getIntent().getAction(); - return (Intent.ACTION_PICK.equals(action) - || Intent.ACTION_GET_CONTENT.equals(action)); - } - - private void launchCropperOrFinish(IImage img) { - Bundle myExtras = getIntent().getExtras(); - - long size = MenuHelper.getImageFileSize(img); - if (size < 0) { - // Return if the image file is not available. - return; - } - - if (size > mVideoSizeLimit) { - DialogInterface.OnClickListener buttonListener = - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }; - new AlertDialog.Builder(this) - .setIcon(android.R.drawable.ic_dialog_info) - .setTitle(R.string.file_info_title) - .setMessage(R.string.video_exceed_mms_limit) - .setNeutralButton(R.string.details_ok, buttonListener) - .show(); - return; - } - - String cropValue = myExtras != null ? myExtras.getString("crop") : null; - if (cropValue != null) { - Bundle newExtras = new Bundle(); - if (cropValue.equals("circle")) { - newExtras.putString("circleCrop", "true"); - } - - Intent cropIntent = new Intent(); - cropIntent.setData(img.fullSizeImageUri()); - cropIntent.setClass(this, CropImage.class); - cropIntent.putExtras(newExtras); - - /* pass through any extras that were passed in */ - cropIntent.putExtras(myExtras); - startActivityForResult(cropIntent, CROP_MSG); - } else { - Intent result = new Intent(null, img.fullSizeImageUri()); - if (myExtras != null && myExtras.getBoolean("return-data")) { - // The size of a transaction should be below 100K. - Bitmap bitmap = img.fullSizeBitmap( - IImage.UNCONSTRAINED, 100 * 1024); - if (bitmap != null) { - result.putExtra("data", bitmap); - } - } - setResult(RESULT_OK, result); - finish(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - switch (requestCode) { - case MenuHelper.RESULT_COMMON_MENU_CROP: { - if (resultCode == RESULT_OK) { - - // The CropImage activity passes back the Uri of the cropped - // image as the Action rather than the Data. - // We store this URI so we can move the selection box to it - // later. - mCropResultUri = Uri.parse(data.getAction()); - } - break; - } - case CROP_MSG: { - if (resultCode == RESULT_OK) { - setResult(resultCode, data); - finish(); - } - break; - } - } - } - - @Override - public void onPause() { - super.onPause(); - mPausing = true; - - mLoader.stop(); - - mGvs.stop(); - - if (mReceiver != null) { - unregisterReceiver(mReceiver); - mReceiver = null; - } - - // Now that we've paused the threads that are using the cursor it is - // safe to close it. - mAllImages.close(); - mAllImages = null; - } - - private void rebake(boolean unmounted, boolean scanning) { - mGvs.stop(); - if (mAllImages != null) { - mAllImages.close(); - mAllImages = null; - } - - if (mMediaScanningDialog != null) { - mMediaScanningDialog.cancel(); - mMediaScanningDialog = null; - } - - if (scanning) { - mMediaScanningDialog = ProgressDialog.show( - this, - null, - getResources().getString(R.string.wait), - true, - true); - } - - mParam = allImages(!unmounted && !scanning); - mAllImages = ImageManager.makeImageList(getContentResolver(), mParam); - - mGvs.setImageList(mAllImages); - mGvs.setDrawAdapter(this); - mGvs.setLoader(mLoader); - mGvs.start(); - mNoImagesView.setVisibility(mAllImages.getCount() > 0 - ? View.GONE - : View.VISIBLE); - } - - @Override - protected void onSaveInstanceState(Bundle state) { - super.onSaveInstanceState(state); - state.putFloat(STATE_SCROLL_POSITION, mScrollPosition); - state.putInt(STATE_SELECTED_INDEX, mSelectedIndex); - } - - @Override - protected void onRestoreInstanceState(Bundle state) { - super.onRestoreInstanceState(state); - mScrollPosition = state.getFloat( - STATE_SCROLL_POSITION, INVALID_POSITION); - mSelectedIndex = state.getInt(STATE_SELECTED_INDEX, 0); - } - - @Override - public void onResume() { - super.onResume(); - - mGvs.setSizeChoice(Integer.parseInt( - mPrefs.getString("pref_gallery_size_key", "1"))); - mGvs.requestFocus(); - - String sortOrder = mPrefs.getString("pref_gallery_sort_key", null); - if (sortOrder != null) { - mSortAscending = sortOrder.equals("ascending"); - } - - mPausing = false; - - // 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"); - - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - 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 - 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); - } - } - }; - registerReceiver(mReceiver, intentFilter); - rebake(false, ImageManager.isMediaScannerScanning( - getContentResolver())); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (isPickIntent()) { - String type = getIntent().resolveType(this); - if (type != null) { - if (isImageType(type)) { - MenuHelper.addCapturePictureMenuItems(menu, this); - } else if (isVideoType(type)) { - MenuHelper.addCaptureVideoMenuItems(menu, this); - } - } - } else { - MenuHelper.addCaptureMenuItems(menu, this); - if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) { - mSlideShowItem = addSlideShowMenu(menu); - } - - MenuItem item = menu.add(Menu.NONE, Menu.NONE, - MenuHelper.POSITION_GALLERY_SETTING, - R.string.camerasettings); - item.setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Intent preferences = new Intent(); - preferences.setClass(ImageGallery.this, - GallerySettings.class); - startActivity(preferences); - return true; - } - }); - item.setAlphabeticShortcut('p'); - item.setIcon(android.R.drawable.ic_menu_preferences); - - item = menu.add(Menu.NONE, Menu.NONE, - MenuHelper.POSITION_MULTISELECT, - R.string.multiselect); - item.setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - if (isInMultiSelectMode()) { - closeMultiSelectMode(); - } else { - openMultiSelectMode(); - } - return true; - } - }); - item.setIcon(R.drawable.ic_menu_multiselect_gallery); - } - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - if (!canHandleEvent()) return false; - if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) { - boolean videoSelected = isVideoSelected(); - // TODO: Only enable slide show if there is at least one image in - // the folder. - if (mSlideShowItem != null) { - mSlideShowItem.setEnabled(!videoSelected); - } - } - - return true; - } - - private boolean isVideoSelected() { - IImage image = getCurrentImage(); - return (image != null) && ImageManager.isVideo(image); - } - - private boolean isImageType(String type) { - return type.equals("vnd.android.cursor.dir/image") - || type.equals("image/*"); - } - - private boolean isVideoType(String type) { - return type.equals("vnd.android.cursor.dir/video") - || type.equals("video/*"); - } - - // According to the intent, setup what we include (image/video) in the - // gallery and the title of the gallery. - private void setupInclusion() { - mInclusion = ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS; - - Intent intent = getIntent(); - if (intent != null) { - String type = intent.resolveType(this); - TextView leftText = (TextView) findViewById(R.id.left_text); - if (type != null) { - if (isImageType(type)) { - mInclusion = ImageManager.INCLUDE_IMAGES; - if (isPickIntent()) { - leftText.setText(R.string.pick_photos_gallery_title); - } else { - leftText.setText(R.string.photos_gallery_title); - } - } - if (isVideoType(type)) { - mInclusion = ImageManager.INCLUDE_VIDEOS; - if (isPickIntent()) { - leftText.setText(R.string.pick_videos_gallery_title); - } else { - leftText.setText(R.string.videos_gallery_title); - } - } - } - Bundle extras = intent.getExtras(); - String title = (extras != null) - ? extras.getString("windowTitle") - : null; - if (title != null && title.length() > 0) { - leftText.setText(title); - } - - if (extras != null) { - mInclusion = (ImageManager.INCLUDE_IMAGES - | ImageManager.INCLUDE_VIDEOS) - & extras.getInt("mediaTypes", mInclusion); - } - - if (extras != null && extras.getBoolean("pick-drm")) { - Log.d(TAG, "pick-drm is true"); - mInclusion = ImageManager.INCLUDE_DRM_IMAGES; - } - } - } - - // Returns the image list parameter which contains the subset of image/video - // we want. - private ImageManager.ImageListParam allImages(boolean storageAvailable) { - if (!storageAvailable) { - return ImageManager.getEmptyImageListParam(); - } else { - Uri uri = getIntent().getData(); - return ImageManager.getImageListParam( - ImageManager.DataLocation.EXTERNAL, - mInclusion, - mSortAscending - ? ImageManager.SORT_ASCENDING - : ImageManager.SORT_DESCENDING, - (uri != null) - ? uri.getQueryParameter("bucketId") - : null); - } - } - - private void toggleMultiSelected(IImage image) { - int original = mMultiSelected.size(); - if (!mMultiSelected.add(image)) { - mMultiSelected.remove(image); - } - mGvs.invalidate(); - if (original == 0) showFooter(); - if (mMultiSelected.size() == 0) hideFooter(); - } - - public void onImageClicked(int index) { - if (index < 0 || index >= mAllImages.getCount()) { - return; - } - mSelectedIndex = index; - mGvs.setSelectedIndex(index); - - IImage image = mAllImages.getImageAt(index); - - if (isInMultiSelectMode()) { - toggleMultiSelected(image); - return; - } - - if (isPickIntent()) { - launchCropperOrFinish(image); - } else { - Intent intent; - if (image instanceof VideoObject) { - intent = new Intent( - Intent.ACTION_VIEW, image.fullSizeImageUri()); - intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, - ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } else { - intent = new Intent(this, ViewImage.class); - intent.putExtra(ViewImage.KEY_IMAGE_LIST, mParam); - intent.setData(image.fullSizeImageUri()); - } - startActivity(intent); - } - } - - public void onImageTapped(int index) { - // In the multiselect mode, once the finger finishes tapping, we hide - // the selection box by setting the selected index to none. However, if - // we use the dpad center key, we will keep the selected index in order - // to show the the selection box. We do this because we have the - // multiselect marker on the images to indicate which of them are - // selected, so we don't need the selection box, but in the dpad case - // we still need the selection box to show as a "cursor". - - if (isInMultiSelectMode()) { - mGvs.setSelectedIndex(GridViewSpecial.INDEX_NONE); - toggleMultiSelected(mAllImages.getImageAt(index)); - } else { - onImageClicked(index); - } - } - - private class CreateContextMenuListener implements - View.OnCreateContextMenuListener { - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenu.ContextMenuInfo menuInfo) { - if (!canHandleEvent()) return; - - IImage image = getCurrentImage(); - - if (image == null) { - return; - } - - boolean isImage = ImageManager.isImage(image); - if (isImage) { - menu.add(R.string.view) - .setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - if (!canHandleEvent()) return false; - onImageClicked(mGvs.getCurrentSelection()); - return true; - } - }); - } - - menu.setHeaderTitle(isImage - ? R.string.context_menu_header - : R.string.video_context_menu_header); - if ((mInclusion & (ImageManager.INCLUDE_IMAGES - | ImageManager.INCLUDE_VIDEOS)) != 0) { - MenuHelper.MenuItemsResult r = MenuHelper.addImageMenuItems( - menu, - MenuHelper.INCLUDE_ALL, - ImageGallery.this, - mHandler, - mDeletePhotoRunnable, - new MenuHelper.MenuInvoker() { - public void run(MenuHelper.MenuCallback cb) { - if (!canHandleEvent()) { - return; - } - cb.run(getCurrentImageUri(), getCurrentImage()); - mGvs.invalidateImage(mGvs.getCurrentSelection()); - } - }); - - if (r != null) { - r.gettingReadyToOpen(menu, image); - } - - if (isImage) { - MenuHelper.enableShowOnMapMenuItem( - menu, MenuHelper.hasLatLngData(image)); - addSlideShowMenu(menu); - } - } - } - } - - public void onLayoutComplete(boolean changed) { - mLayoutComplete = true; - if (mCropResultUri != null) { - IImage image = mAllImages.getImageForUri(mCropResultUri); - mCropResultUri = null; - if (image != null) { - mSelectedIndex = mAllImages.getImageIndex(image); - } - } - mGvs.setSelectedIndex(mSelectedIndex); - if (mScrollPosition == INVALID_POSITION) { - if (mSortAscending) { - mGvs.scrollTo(0, mGvs.getHeight()); - } else { - mGvs.scrollToImage(0); - } - } else if (mConfigurationChanged) { - mConfigurationChanged = false; - mGvs.scrollTo(mScrollPosition); - if (mGvs.getCurrentSelection() != GridViewSpecial.INDEX_NONE) { - mGvs.scrollToVisible(mSelectedIndex); - } - } else { - mGvs.scrollTo(mScrollPosition); - } - } - - public void onScroll(float scrollPosition) { - mScrollPosition = scrollPosition; - } - - private Drawable mVideoOverlay; - private Drawable mVideoMmsErrorOverlay; - private Drawable mMultiSelectTrue; - private Drawable mMultiSelectFalse; - - // mSrcRect and mDstRect are only used in drawImage, but we put them as - // instance variables to reduce the memory allocation overhead because - // drawImage() is called a lot. - private final Rect mSrcRect = new Rect(); - private final Rect mDstRect = new Rect(); - - private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - - public void drawImage(Canvas canvas, IImage image, - Bitmap b, int xPos, int yPos, int w, int h) { - if (b != null) { - // if the image is close to the target size then crop, - // otherwise scale both the bitmap and the view should be - // square but I suppose that could change in the future. - - int bw = b.getWidth(); - int bh = b.getHeight(); - - int deltaW = bw - w; - int deltaH = bh - h; - - if (deltaW >= 0 && deltaW < 10 && - deltaH >= 0 && deltaH < 10) { - int halfDeltaW = deltaW / 2; - int halfDeltaH = deltaH / 2; - mSrcRect.set(0 + halfDeltaW, 0 + halfDeltaH, - bw - halfDeltaW, bh - halfDeltaH); - mDstRect.set(xPos, yPos, xPos + w, yPos + h); - canvas.drawBitmap(b, mSrcRect, mDstRect, null); - } else { - mSrcRect.set(0, 0, bw, bh); - mDstRect.set(xPos, yPos, xPos + w, yPos + h); - canvas.drawBitmap(b, mSrcRect, mDstRect, mPaint); - } - } else { - // If the thumbnail cannot be drawn, put up an error icon - // instead - Bitmap error = getErrorBitmap(image); - int width = error.getWidth(); - int height = error.getHeight(); - mSrcRect.set(0, 0, width, height); - int left = (w - width) / 2 + xPos; - int top = (w - height) / 2 + yPos; - mDstRect.set(left, top, left + width, top + height); - canvas.drawBitmap(error, mSrcRect, mDstRect, null); - } - - if (ImageManager.isVideo(image)) { - Drawable overlay = null; - long size = MenuHelper.getImageFileSize(image); - if (size >= 0 && size <= mVideoSizeLimit) { - if (mVideoOverlay == null) { - mVideoOverlay = getResources().getDrawable( - R.drawable.ic_gallery_video_overlay); - } - overlay = mVideoOverlay; - } else { - if (mVideoMmsErrorOverlay == null) { - mVideoMmsErrorOverlay = getResources().getDrawable( - R.drawable.ic_error_mms_video_overlay); - } - overlay = mVideoMmsErrorOverlay; - Paint paint = new Paint(); - paint.setARGB(0x80, 0x00, 0x00, 0x00); - canvas.drawRect(xPos, yPos, xPos + w, yPos + h, paint); - } - int width = overlay.getIntrinsicWidth(); - int height = overlay.getIntrinsicHeight(); - int left = (w - width) / 2 + xPos; - int top = (h - height) / 2 + yPos; - mSrcRect.set(left, top, left + width, top + height); - overlay.setBounds(mSrcRect); - overlay.draw(canvas); - } - } - - public boolean needsDecoration() { - return (mMultiSelected != null); - } - - public void drawDecoration(Canvas canvas, IImage image, - int xPos, int yPos, int w, int h) { - if (mMultiSelected != null) { - initializeMultiSelectDrawables(); - - Drawable checkBox = mMultiSelected.contains(image) - ? mMultiSelectTrue - : mMultiSelectFalse; - int width = checkBox.getIntrinsicWidth(); - int height = checkBox.getIntrinsicHeight(); - int left = 5 + xPos; - int top = h - height - 5 + yPos; - mSrcRect.set(left, top, left + width, top + height); - checkBox.setBounds(mSrcRect); - checkBox.draw(canvas); - } - } - - private void initializeMultiSelectDrawables() { - if (mMultiSelectTrue == null) { - mMultiSelectTrue = getResources() - .getDrawable(R.drawable.btn_check_buttonless_on); - } - if (mMultiSelectFalse == null) { - mMultiSelectFalse = getResources() - .getDrawable(R.drawable.btn_check_buttonless_off); - } - } - - private Bitmap mMissingImageThumbnailBitmap; - private Bitmap mMissingVideoThumbnailBitmap; - - // Create this bitmap lazily, and only once for all the ImageBlocks to - // use - public Bitmap getErrorBitmap(IImage image) { - if (ImageManager.isImage(image)) { - if (mMissingImageThumbnailBitmap == null) { - mMissingImageThumbnailBitmap = BitmapFactory.decodeResource( - getResources(), - R.drawable.ic_missing_thumbnail_picture); - } - return mMissingImageThumbnailBitmap; - } else { - if (mMissingVideoThumbnailBitmap == null) { - mMissingVideoThumbnailBitmap = BitmapFactory.decodeResource( - getResources(), R.drawable.ic_missing_thumbnail_video); - } - return mMissingVideoThumbnailBitmap; - } - } - - private Animation mFooterAppear; - private Animation mFooterDisappear; - - private void showFooter() { - mFooterOrganizeView.setVisibility(View.VISIBLE); - if (mFooterAppear == null) { - mFooterAppear = AnimationUtils.loadAnimation( - this, R.anim.footer_appear); - } - mFooterOrganizeView.startAnimation(mFooterAppear); - } - - private void hideFooter() { - if (mFooterOrganizeView.getVisibility() != View.GONE) { - mFooterOrganizeView.setVisibility(View.GONE); - if (mFooterDisappear == null) { - mFooterDisappear = AnimationUtils.loadAnimation( - this, R.anim.footer_disappear); - } - mFooterOrganizeView.startAnimation(mFooterDisappear); - } - } - - private String getShareMultipleMimeType() { - final int FLAG_IMAGE = 1, FLAG_VIDEO = 2; - int flag = 0; - for (IImage image : mMultiSelected) { - flag |= ImageManager.isImage(image) ? FLAG_IMAGE : FLAG_VIDEO; - } - return flag == FLAG_IMAGE - ? "image/*" - : flag == FLAG_VIDEO ? "video/*" : "*/*"; - } - - private void onShareMultipleClicked() { - if (mMultiSelected == null) return; - if (mMultiSelected.size() > 1) { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND_MULTIPLE); - - String mimeType = getShareMultipleMimeType(); - intent.setType(mimeType); - ArrayList<Parcelable> list = new ArrayList<Parcelable>(); - for (IImage image : mMultiSelected) { - list.add(image.fullSizeImageUri()); - } - intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, list); - try { - startActivity(Intent.createChooser( - intent, getText(R.string.send_media_files))); - } catch (android.content.ActivityNotFoundException ex) { - Toast.makeText(this, R.string.no_way_to_share, - Toast.LENGTH_SHORT).show(); - } - } else if (mMultiSelected.size() == 1) { - IImage image = mMultiSelected.iterator().next(); - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - String mimeType = image.getMimeType(); - intent.setType(mimeType); - intent.putExtra(Intent.EXTRA_STREAM, image.fullSizeImageUri()); - boolean isImage = ImageManager.isImage(image); - try { - startActivity(Intent.createChooser(intent, getText( - isImage ? R.string.sendImage : R.string.sendVideo))); - } catch (android.content.ActivityNotFoundException ex) { - Toast.makeText(this, isImage - ? R.string.no_way_to_share_image - : R.string.no_way_to_share_video, - Toast.LENGTH_SHORT).show(); - } - } - } - - private void onDeleteMultipleClicked() { - if (mMultiSelected == null) return; - Runnable action = new Runnable() { - public void run() { - ArrayList<Uri> uriList = new ArrayList<Uri>(); - for (IImage image : mMultiSelected) { - uriList.add(image.fullSizeImageUri()); - } - closeMultiSelectMode(); - Intent intent = new Intent(ImageGallery.this, - DeleteImage.class); - intent.putExtra("delete-uris", uriList); - try { - startActivity(intent); - } catch (ActivityNotFoundException ex) { - Log.e(TAG, "Delete images fail", ex); - } - } - }; - MenuHelper.deleteMultiple(this, action); - } - - private boolean isInMultiSelectMode() { - return mMultiSelected != null; - } - - private void closeMultiSelectMode() { - if (mMultiSelected == null) return; - mMultiSelected = null; - mGvs.invalidate(); - hideFooter(); - } - - private void openMultiSelectMode() { - if (mMultiSelected != null) return; - mMultiSelected = new HashSet<IImage>(); - mGvs.invalidate(); - } - -} diff --git a/src/com/android/camera/ImageLoader.java b/src/com/android/camera/ImageLoader.java deleted file mode 100644 index a394508a..00000000 --- a/src/com/android/camera/ImageLoader.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.camera.gallery.IImage; - -import android.content.ContentResolver; -import android.graphics.Bitmap; -import android.os.Handler; -import android.provider.MediaStore; -import android.util.Log; - -import java.util.ArrayList; - -/** - * A dedicated decoding thread used by ImageGallery. - */ -public class ImageLoader { - @SuppressWarnings("unused") - private static final String TAG = "ImageLoader"; - - // Queue of work to do in the worker thread. The work is done in order. - private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>(); - - // the worker thread and a done flag so we know when to exit - private boolean mDone; - private Thread mDecodeThread; - private ContentResolver mCr; - - public interface LoadedCallback { - public void run(Bitmap result); - } - - public void getBitmap(IImage image, - LoadedCallback imageLoadedRunnable, - int tag) { - if (mDecodeThread == null) { - start(); - } - synchronized (mQueue) { - WorkItem w = new WorkItem(image, imageLoadedRunnable, tag); - mQueue.add(w); - mQueue.notifyAll(); - } - } - - public boolean cancel(final IImage image) { - synchronized (mQueue) { - int index = findItem(image); - if (index >= 0) { - mQueue.remove(index); - return true; - } else { - return false; - } - } - } - - // The caller should hold mQueue lock. - private int findItem(IImage image) { - for (int i = 0; i < mQueue.size(); i++) { - if (mQueue.get(i).mImage == image) { - return i; - } - } - return -1; - } - - // Clear the queue. Returns an array of tags that were in the queue. - public int[] clearQueue() { - synchronized (mQueue) { - int n = mQueue.size(); - int[] tags = new int[n]; - for (int i = 0; i < n; i++) { - tags[i] = mQueue.get(i).mTag; - } - mQueue.clear(); - return tags; - } - } - - private static class WorkItem { - IImage mImage; - LoadedCallback mOnLoadedRunnable; - int mTag; - - WorkItem(IImage image, LoadedCallback onLoadedRunnable, int tag) { - mImage = image; - mOnLoadedRunnable = onLoadedRunnable; - mTag = tag; - } - } - - public ImageLoader(ContentResolver cr, Handler handler) { - mCr = cr; - start(); - } - - private class WorkerThread implements Runnable { - - // Pick off items on the queue, one by one, and compute their bitmap. - // Place the resulting bitmap in the cache, then call back by executing - // the given runnable so things can get updated appropriately. - public void run() { - while (true) { - WorkItem workItem = null; - synchronized (mQueue) { - if (mDone) { - break; - } - if (!mQueue.isEmpty()) { - workItem = mQueue.remove(0); - } else { - try { - mQueue.wait(); - } catch (InterruptedException ex) { - // ignore the exception - } - continue; - } - } - - final Bitmap b = workItem.mImage.miniThumbBitmap(); - - if (workItem.mOnLoadedRunnable != null) { - workItem.mOnLoadedRunnable.run(b); - } - } - } - } - - private void start() { - if (mDecodeThread != null) { - return; - } - - mDone = false; - Thread t = new Thread(new WorkerThread()); - t.setName("image-loader"); - mDecodeThread = t; - t.start(); - } - - public void stop() { - synchronized (mQueue) { - mDone = true; - mQueue.notifyAll(); - } - if (mDecodeThread != null) { - try { - Thread t = mDecodeThread; - BitmapManager.instance().cancelThreadDecoding(t, mCr); - t.join(); - mDecodeThread = null; - } catch (InterruptedException ex) { - // so now what? - } - } - } -} diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index f2c931da..bdf78483 100644 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -410,10 +410,6 @@ public class ImageManager { public void close() { } - public HashMap<String, String> getBucketIds() { - return new HashMap<String, String>(); - } - public int getCount() { return 0; } @@ -459,12 +455,6 @@ public class ImageManager { return param; } - public static ImageListParam getEmptyImageListParam() { - ImageListParam param = new ImageListParam(); - param.mIsEmptyImageList = true; - return param; - } - public static IImageList makeImageList(ContentResolver cr, DataLocation location, int inclusion, int sort, String bucketId) { ImageListParam param = getImageListParam(location, inclusion, sort, @@ -472,10 +462,6 @@ public class ImageManager { return makeImageList(cr, param); } - public static IImageList makeEmptyImageList() { - return makeImageList(null, getEmptyImageListParam()); - } - public static IImageList makeSingleImageList(ContentResolver cr, Uri uri) { return makeImageList(cr, getSingleImageListParam(uri)); } diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java index 453d6290..0d949b2b 100644 --- a/src/com/android/camera/MenuHelper.java +++ b/src/com/android/camera/MenuHelper.java @@ -887,20 +887,6 @@ public class MenuHelper { } } - public static void deleteMultiple(Context context, Runnable action) { - boolean needConfirm = PreferenceManager - .getDefaultSharedPreferences(context) - .getBoolean("pref_gallery_confirm_delete_key", true); - if (!needConfirm) { - if (action != null) action.run(); - } else { - String title = context.getString(R.string.confirm_delete_title); - String message = context.getString( - R.string.confirm_delete_multiple_message); - confirmAction(context, title, message, action); - } - } - public static void confirmAction(Context context, String title, String message, final Runnable action) { OnClickListener listener = new OnClickListener() { @@ -969,55 +955,6 @@ public class MenuHelper { } } - static void addCapturePictureMenuItems(Menu menu, final Activity activity) { - menu.add(Menu.NONE, Menu.NONE, POSITION_CAPTURE_PICTURE, - R.string.capture_picture) - .setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - return onCapturePictureClicked(activity); - } - }).setIcon(android.R.drawable.ic_menu_camera); - } - - private static boolean onCapturePictureClicked(Activity activity) { - Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - try { - activity.startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - // Ignore exception - } - return true; - } - - static void addCaptureVideoMenuItems(Menu menu, final Activity activity) { - menu.add(Menu.NONE, Menu.NONE, POSITION_CAPTURE_VIDEO, - R.string.capture_video) - .setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - return onCaptureVideoClicked(activity); - } - }).setIcon(R.drawable.ic_menu_camera_video_view); - } - - private static boolean onCaptureVideoClicked(Activity activity) { - Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - try { - activity.startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - // Ignore exception - } - return true; - } - - public static void addCaptureMenuItems(Menu menu, final Activity activity) { - addCapturePictureMenuItems(menu, activity); - addCaptureVideoMenuItems(menu, activity); - } - public static String formatDuration(final Context context, int durationMs) { int duration = durationMs / 1000; diff --git a/src/com/android/camera/MovieView.java b/src/com/android/camera/MovieView.java deleted file mode 100644 index 0f4df52f..00000000 --- a/src/com/android/camera/MovieView.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.content.Intent; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.provider.MediaStore; -import android.util.Log; -import android.view.View; - -/** - * This activity plays a video from a specified URI. - */ -public class MovieView extends NoSearchActivity { - private static final String TAG = "MovieView"; - - private MovieViewControl mControl; - private boolean mFinishOnCompletion; - private boolean mResumed = false; // Whether this activity has been resumed. - private boolean mFocused = false; // Whether this window has focus. - private boolean mControlResumed = false; // Whether the MovieViewControl is resumed. - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.movie_view); - View rootView = findViewById(R.id.root); - Intent intent = getIntent(); - mControl = new MovieViewControl(rootView, this, intent.getData()) { - @Override - public void onCompletion() { - if (mFinishOnCompletion) { - finish(); - } - } - }; - if (intent.hasExtra(MediaStore.EXTRA_SCREEN_ORIENTATION)) { - int orientation = intent.getIntExtra( - MediaStore.EXTRA_SCREEN_ORIENTATION, - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - if (orientation != getRequestedOrientation()) { - setRequestedOrientation(orientation); - } - } - mFinishOnCompletion = intent.getBooleanExtra( - MediaStore.EXTRA_FINISH_ON_COMPLETION, true); - } - - @Override - public void onPause() { - super.onPause(); - mResumed = false; - if (mControlResumed) { - mControl.onPause(); - mControlResumed = false; - } - } - - @Override - public void onResume() { - super.onResume(); - mResumed = true; - if (mFocused && mResumed && !mControlResumed) { - mControl.onResume(); - mControlResumed = true; - } - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - mFocused = hasFocus; - if (mFocused && mResumed && !mControlResumed) { - mControl.onResume(); - mControlResumed = true; - } - } -} diff --git a/src/com/android/camera/MovieViewControl.java b/src/com/android/camera/MovieViewControl.java deleted file mode 100644 index 737433b7..00000000 --- a/src/com/android/camera/MovieViewControl.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2009 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.AlertDialog; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.database.Cursor; -import android.database.sqlite.SQLiteException; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.Handler; -import android.provider.MediaStore; -import android.provider.MediaStore.Video; -import android.view.View; -import android.widget.MediaController; -import android.widget.VideoView; - -public class MovieViewControl implements MediaPlayer.OnErrorListener, - MediaPlayer.OnCompletionListener { - - @SuppressWarnings("unused") - private static final String TAG = "MovieViewControl"; - - private static final int ONE_MINUTE = 60 * 1000; - private static final int TWO_MINUTES = 2 * ONE_MINUTE; - private static final int FIVE_MINUTES = 5 * ONE_MINUTE; - - // Copied from MediaPlaybackService in the Music Player app. Should be - // public, but isn't. - private static final String SERVICECMD = - "com.android.music.musicservicecommand"; - private static final String CMDNAME = "command"; - private static final String CMDPAUSE = "pause"; - - private final VideoView mVideoView; - private final View mProgressView; - private final Uri mUri; - private final ContentResolver mContentResolver; - - // State maintained for proper onPause/OnResume behaviour. - private int mPositionWhenPaused = -1; - private boolean mWasPlayingWhenPaused = false; - private MediaController mMediaController; - - Handler mHandler = new Handler(); - - Runnable mPlayingChecker = new Runnable() { - public void run() { - if (mVideoView.isPlaying()) { - mProgressView.setVisibility(View.GONE); - } else { - mHandler.postDelayed(mPlayingChecker, 250); - } - } - }; - - public MovieViewControl(View rootView, Context context, Uri videoUri) { - mContentResolver = context.getContentResolver(); - mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); - mProgressView = rootView.findViewById(R.id.progress_indicator); - - mUri = videoUri; - - // For streams that we expect to be slow to start up, show a - // progress spinner until playback starts. - String scheme = mUri.getScheme(); - if ("http".equalsIgnoreCase(scheme) - || "rtsp".equalsIgnoreCase(scheme)) { - mHandler.postDelayed(mPlayingChecker, 250); - } else { - mProgressView.setVisibility(View.GONE); - } - - mVideoView.setOnErrorListener(this); - mVideoView.setOnCompletionListener(this); - mVideoView.setVideoURI(mUri); - mMediaController = new MediaController(context); - mVideoView.setMediaController(mMediaController); - - // make the video view handle keys for seeking and pausing - mVideoView.requestFocus(); - - Intent i = new Intent(SERVICECMD); - i.putExtra(CMDNAME, CMDPAUSE); - context.sendBroadcast(i); - - final Integer bookmark = getBookmark(); - if (bookmark != null) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.resume_playing_title); - builder.setMessage(String.format( - context.getString(R.string.resume_playing_message), - MenuHelper.formatDuration(context, bookmark))); - builder.setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - onCompletion(); - }}); - builder.setPositiveButton(R.string.resume_playing_resume, - new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mVideoView.seekTo(bookmark); - mVideoView.start(); - }}); - builder.setNegativeButton(R.string.resume_playing_restart, - new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mVideoView.start(); - }}); - builder.show(); - } else { - mVideoView.start(); - } - } - - private static boolean uriSupportsBookmarks(Uri uri) { - String scheme = uri.getScheme(); - String authority = uri.getAuthority(); - return ("content".equalsIgnoreCase(scheme) - && MediaStore.AUTHORITY.equalsIgnoreCase(authority)); - } - - private Integer getBookmark() { - if (!uriSupportsBookmarks(mUri)) { - return null; - } - - String[] projection = new String[] { - Video.VideoColumns.DURATION, - Video.VideoColumns.BOOKMARK}; - - try { - Cursor cursor = mContentResolver.query( - mUri, projection, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - int duration = getCursorInteger(cursor, 0); - int bookmark = getCursorInteger(cursor, 1); - if ((bookmark < TWO_MINUTES) - || (duration < FIVE_MINUTES) - || (bookmark > (duration - ONE_MINUTE))) { - return null; - } - return Integer.valueOf(bookmark); - } - } finally { - cursor.close(); - } - } - } catch (SQLiteException e) { - // ignore - } - - return null; - } - - private static int getCursorInteger(Cursor cursor, int index) { - try { - return cursor.getInt(index); - } catch (SQLiteException e) { - return 0; - } catch (NumberFormatException e) { - return 0; - } - - } - - private void setBookmark(int bookmark) { - if (!uriSupportsBookmarks(mUri)) { - return; - } - - ContentValues values = new ContentValues(); - values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark)); - try { - mContentResolver.update(mUri, values, null, null); - } catch (SecurityException ex) { - // Ignore, can happen if we try to set the bookmark on a read-only - // resource such as a video attached to GMail. - } catch (SQLiteException e) { - // ignore. can happen if the content doesn't support a bookmark - // column. - } catch (UnsupportedOperationException e) { - // ignore. can happen if the external volume is already detached. - } - } - - public void onPause() { - mHandler.removeCallbacksAndMessages(null); - setBookmark(mVideoView.getCurrentPosition()); - - mPositionWhenPaused = mVideoView.getCurrentPosition(); - mWasPlayingWhenPaused = mVideoView.isPlaying(); - mVideoView.stopPlayback(); - } - - public void onResume() { - if (mPositionWhenPaused >= 0) { - mVideoView.setVideoURI(mUri); - mVideoView.seekTo(mPositionWhenPaused); - mPositionWhenPaused = -1; - if (mWasPlayingWhenPaused) { - mMediaController.show(0); - } - } - } - - public boolean onError(MediaPlayer player, int arg1, int arg2) { - mHandler.removeCallbacksAndMessages(null); - mProgressView.setVisibility(View.GONE); - return false; - } - - public void onCompletion(MediaPlayer mp) { - onCompletion(); - } - - public void onCompletion() { - } -} diff --git a/src/com/android/camera/PhotoAppWidgetBind.java b/src/com/android/camera/PhotoAppWidgetBind.java deleted file mode 100644 index 5c2aa50b..00000000 --- a/src/com/android/camera/PhotoAppWidgetBind.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2009 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.camera.PhotoAppWidgetProvider.PhotoDatabaseHelper; - -import android.app.Activity; -import android.appwidget.AppWidgetManager; -import android.content.Intent; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.util.Log; -import android.widget.RemoteViews; - -import java.util.ArrayList; - -class PhotoAppWidgetBind extends NoSearchActivity { - private static final String TAG = "PhotoAppWidgetBind"; - private static final String EXTRA_APPWIDGET_BITMAPS = - "com.android.camera.appwidgetbitmaps"; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - finish(); - - // The caller has requested that we bind a given bitmap to a specific - // appWidgetId, which probably is happening during a Launcher upgrade. - // This is dangerous because the caller could set bitmaps on - // appWidgetIds they don't own, so we guard this call at the manifest - // level by requiring the BIND_APPWIDGET permission. - - final Intent intent = getIntent(); - final Bundle extras = intent.getExtras(); - - final int[] appWidgetIds = - extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); - final ArrayList<Bitmap> bitmaps = - extras.getParcelableArrayList(EXTRA_APPWIDGET_BITMAPS); - - if (appWidgetIds == null || bitmaps == null - || appWidgetIds.length != bitmaps.size()) { - Log.e(TAG, "Problem parsing photo widget bind request"); - return; - } - - AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); - for (int i = 0; i < appWidgetIds.length; i++) { - // Store the cropped photo in our database - int appWidgetId = appWidgetIds[i]; - helper.setPhoto(appWidgetId, bitmaps.get(i)); - - // Push newly updated widget to surface - RemoteViews views = - PhotoAppWidgetProvider.buildUpdate(this, appWidgetId, - helper); - appWidgetManager.updateAppWidget(new int[] { appWidgetId }, views); - } - helper.close(); - } -} diff --git a/src/com/android/camera/PhotoAppWidgetConfigure.java b/src/com/android/camera/PhotoAppWidgetConfigure.java deleted file mode 100644 index 76174c79..00000000 --- a/src/com/android/camera/PhotoAppWidgetConfigure.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2009 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.camera.PhotoAppWidgetProvider.PhotoDatabaseHelper; - -import android.app.Activity; -import android.appwidget.AppWidgetManager; -import android.content.Intent; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.util.DisplayMetrics; -import android.widget.RemoteViews; - -public class PhotoAppWidgetConfigure extends NoSearchActivity { - - @SuppressWarnings("unused") - private static final String TAG = "PhotoAppWidgetConfigure"; - static final int REQUEST_GET_PHOTO = 2; - - int mAppWidgetId = -1; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Someone is requesting that we configure the given mAppWidgetId, which - // means we prompt the user to pick and crop a photo. - - mAppWidgetId = getIntent().getIntExtra( - AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - if (mAppWidgetId == -1) { - setResult(Activity.RESULT_CANCELED); - finish(); - } - - // Assume the widget will be 1/4 of the screen. - // This will be slightly too large, but there is not a good way to know the - // actual widget size from here. The image will be scaled to fit since the layout - // file specifies android:scaleType="centerCrop" - DisplayMetrics display = getResources().getDisplayMetrics(); - int maxDimension = Math.max(display.heightPixels, display.widthPixels); - maxDimension /= 2; - - // TODO: Adjust the PhotoFrame's image size to avoid on the fly scaling - Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); - intent.setType("image/*"); - intent.putExtra("crop", "true"); - intent.putExtra("aspectX", 1); - intent.putExtra("aspectY", 1); - intent.putExtra("outputX", maxDimension); - intent.putExtra("outputY", maxDimension); - intent.putExtra("noFaceDetection", true); - intent.putExtra("return-data", true); - - startActivityForResult(intent, REQUEST_GET_PHOTO); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - if (resultCode == RESULT_OK && mAppWidgetId != -1) { - // Store the cropped photo in our database - Bitmap bitmap = (Bitmap) data.getParcelableExtra("data"); - - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); - if (helper.setPhoto(mAppWidgetId, bitmap)) { - resultCode = Activity.RESULT_OK; - - // Push newly updated widget to surface - RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, - mAppWidgetId, helper); - AppWidgetManager appWidgetManager = - AppWidgetManager.getInstance(this); - appWidgetManager.updateAppWidget(new int[] {mAppWidgetId}, - views); - } - helper.close(); - } else { - resultCode = Activity.RESULT_CANCELED; - } - - // Make sure we pass back the original mAppWidgetId - Intent resultValue = new Intent(); - resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); - setResult(resultCode, resultValue); - finish(); - } - -} diff --git a/src/com/android/camera/PhotoAppWidgetProvider.java b/src/com/android/camera/PhotoAppWidgetProvider.java deleted file mode 100644 index da680b41..00000000 --- a/src/com/android/camera/PhotoAppWidgetProvider.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2009 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.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteOpenHelper; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.util.Log; -import android.widget.RemoteViews; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -/** - * Simple widget to show a user-selected picture. - */ -public class PhotoAppWidgetProvider extends AppWidgetProvider { - private static final String TAG = "PhotoAppWidgetProvider"; - private static final boolean LOGD = true; - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, - int[] appWidgetIds) { - // Update each requested appWidgetId with its unique photo - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context); - for (int appWidgetId : appWidgetIds) { - int[] specificAppWidget = new int[] { appWidgetId }; - RemoteViews views = buildUpdate(context, appWidgetId, helper); - if (LOGD) { - Log.d(TAG, "sending out views=" + views - + " for id=" + appWidgetId); - } - appWidgetManager.updateAppWidget(specificAppWidget, views); - } - helper.close(); - } - - @Override - public void onDeleted(Context context, int[] appWidgetIds) { - // Clean deleted photos out of our database - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context); - for (int appWidgetId : appWidgetIds) { - helper.deletePhoto(appWidgetId); - } - helper.close(); - } - - /** - * Load photo for given widget and build {@link RemoteViews} for it. - */ - static RemoteViews buildUpdate(Context context, int appWidgetId, - PhotoDatabaseHelper helper) { - RemoteViews views = null; - Bitmap bitmap = helper.getPhoto(appWidgetId); - if (bitmap != null) { - views = new RemoteViews(context.getPackageName(), - R.layout.photo_frame); - views.setImageViewBitmap(R.id.photo, bitmap); - } - return views; - } - - static class PhotoDatabaseHelper extends SQLiteOpenHelper { - private static final String DATABASE_NAME = "launcher.db"; - - private static final int DATABASE_VERSION = 2; - - static final String TABLE_PHOTOS = "photos"; - static final String FIELD_APPWIDGET_ID = "appWidgetId"; - static final String FIELD_PHOTO_BLOB = "photoBlob"; - - PhotoDatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" + - FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY," + - FIELD_PHOTO_BLOB + " BLOB" + - ");"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, - int newVersion) { - int version = oldVersion; - - if (version != DATABASE_VERSION) { - Log.w(TAG, "Destroying all old data."); - db.execSQL("DROP TABLE IF EXISTS " + TABLE_PHOTOS); - onCreate(db); - } - } - - /** - * Store the given bitmap in this database for the given appWidgetId. - */ - public boolean setPhoto(int appWidgetId, Bitmap bitmap) { - boolean success = false; - try { - // Try go guesstimate how much space the icon will take when - // serialized to avoid unnecessary allocations/copies during - // the write. - int size = bitmap.getWidth() * bitmap.getHeight() * 4; - ByteArrayOutputStream out = new ByteArrayOutputStream(size); - bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); - out.flush(); - out.close(); - - ContentValues values = new ContentValues(); - values.put(PhotoDatabaseHelper.FIELD_APPWIDGET_ID, appWidgetId); - values.put(PhotoDatabaseHelper.FIELD_PHOTO_BLOB, - out.toByteArray()); - - SQLiteDatabase db = getWritableDatabase(); - db.insertOrThrow(PhotoDatabaseHelper.TABLE_PHOTOS, null, - values); - - success = true; - } catch (SQLiteException e) { - Log.e(TAG, "Could not open database", e); - } catch (IOException e) { - Log.e(TAG, "Could not serialize photo", e); - } - if (LOGD) { - Log.d(TAG, "setPhoto success=" + success); - } - return success; - } - - static final String[] PHOTOS_PROJECTION = { - FIELD_PHOTO_BLOB, - }; - - static final int INDEX_PHOTO_BLOB = 0; - - /** - * Inflate and return a bitmap for the given appWidgetId. - */ - public Bitmap getPhoto(int appWidgetId) { - Cursor c = null; - Bitmap bitmap = null; - try { - SQLiteDatabase db = getReadableDatabase(); - String selection = String.format("%s=%d", FIELD_APPWIDGET_ID, - appWidgetId); - c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION, selection, null, - null, null, null, null); - - if (c != null && LOGD) { - Log.d(TAG, "getPhoto query count=" + c.getCount()); - } - - if (c != null && c.moveToFirst()) { - byte[] data = c.getBlob(INDEX_PHOTO_BLOB); - if (data != null) { - bitmap = BitmapFactory.decodeByteArray(data, 0, - data.length); - } - } - } catch (SQLiteException e) { - Log.e(TAG, "Could not load photo from database", e); - } finally { - if (c != null) { - c.close(); - } - } - return bitmap; - } - - /** - * Remove any bitmap associated with the given appWidgetId. - */ - public void deletePhoto(int appWidgetId) { - try { - SQLiteDatabase db = getWritableDatabase(); - String whereClause = String.format("%s=%d", FIELD_APPWIDGET_ID, - appWidgetId); - db.delete(TABLE_PHOTOS, whereClause, null); - } catch (SQLiteException e) { - Log.e(TAG, "Could not delete photo from database", e); - } - } - } - -} - diff --git a/src/com/android/camera/PickWallpaper.java b/src/com/android/camera/PickWallpaper.java deleted file mode 100644 index b9bff5ac..00000000 --- a/src/com/android/camera/PickWallpaper.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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; - -/** - * Wallpaper picker for the camera application. - * This just redirects to the standard pick action. - */ -public class PickWallpaper extends Wallpaper { -} diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java index d44435aa..6f559e9c 100644 --- a/src/com/android/camera/Util.java +++ b/src/com/android/camera/Util.java @@ -361,16 +361,6 @@ public class Util { } } - public static synchronized OnClickListener getNullOnClickListener() { - if (sNullOnClickListener == null) { - sNullOnClickListener = new OnClickListener() { - public void onClick(View v) { - } - }; - } - return sNullOnClickListener; - } - public static void Assert(boolean cond) { if (!cond) { throw new AssertionError(); diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java deleted file mode 100644 index 7a334117..00000000 --- a/src/com/android/camera/ViewImage.java +++ /dev/null @@ -1,1300 +0,0 @@ -/* - * 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.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.provider.MediaStore; -import android.util.AttributeSet; -import android.util.Log; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.View.OnTouchListener; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.Toast; -import android.widget.ZoomButtonsController; - -import com.android.camera.gallery.IImage; -import com.android.camera.gallery.IImageList; -import com.android.camera.gallery.VideoObject; - -import java.util.Random; - -// This activity can display a whole picture and navigate them in a specific -// gallery. It has two modes: normal mode and slide show mode. In normal mode -// the user view one image at a time, and can click "previous" and "next" -// button to see the previous or next image. In slide show mode it shows one -// image after another, with some transition effect. -public class ViewImage extends NoSearchActivity implements View.OnClickListener { - private static final String PREF_SLIDESHOW_REPEAT = - "pref_gallery_slideshow_repeat_key"; - private static final String PREF_SHUFFLE_SLIDESHOW = - "pref_gallery_slideshow_shuffle_key"; - private static final String STATE_URI = "uri"; - private static final String STATE_SLIDESHOW = "slideshow"; - private static final String EXTRA_SLIDESHOW = "slideshow"; - private static final String TAG = "ViewImage"; - - private ImageGetter mGetter; - private Uri mSavedUri; - boolean mPaused = true; - private boolean mShowControls = true; - - // Choices for what adjacents to load. - private static final int[] sOrderAdjacents = new int[] {0, 1, -1}; - private static final int[] sOrderSlideshow = new int[] {0}; - - final GetterHandler mHandler = new GetterHandler(); - - private final Random mRandom = new Random(System.currentTimeMillis()); - private int [] mShuffleOrder = null; - private boolean mUseShuffleOrder = false; - private boolean mSlideShowLoop = false; - - static final int MODE_NORMAL = 1; - static final int MODE_SLIDESHOW = 2; - private int mMode = MODE_NORMAL; - - private boolean mFullScreenInNormalMode; - private boolean mShowActionIcons; - private View mActionIconPanel; - - private int mSlideShowInterval; - private int mLastSlideShowImage; - int mCurrentPosition = 0; - - // represents which style animation to use - private int mAnimationIndex; - private Animation [] mSlideShowInAnimation; - private Animation [] mSlideShowOutAnimation; - - private SharedPreferences mPrefs; - - private View mNextImageView; - private View mPrevImageView; - private final Animation mHideNextImageViewAnimation = - new AlphaAnimation(1F, 0F); - private final Animation mHidePrevImageViewAnimation = - new AlphaAnimation(1F, 0F); - private final Animation mShowNextImageViewAnimation = - new AlphaAnimation(0F, 1F); - private final Animation mShowPrevImageViewAnimation = - new AlphaAnimation(0F, 1F); - - public static final String KEY_IMAGE_LIST = "image_list"; - private static final String STATE_SHOW_CONTROLS = "show_controls"; - - IImageList mAllImages; - - private ImageManager.ImageListParam mParam; - - private int mSlideShowImageCurrent = 0; - private final ImageViewTouchBase [] mSlideShowImageViews = - new ImageViewTouchBase[2]; - - GestureDetector mGestureDetector; - private ZoomButtonsController mZoomButtonsController; - - // The image view displayed for normal mode. - private ImageViewTouch mImageView; - // This is the cache for thumbnail bitmaps. - private BitmapCache mCache; - private MenuHelper.MenuItemsResult mImageMenuRunnable; - private final Runnable mDismissOnScreenControlRunner = new Runnable() { - public void run() { - hideOnScreenControls(); - } - }; - - private void updateNextPrevControls() { - boolean showPrev = mCurrentPosition > 0; - boolean showNext = mCurrentPosition < mAllImages.getCount() - 1; - - boolean prevIsVisible = mPrevImageView.getVisibility() == View.VISIBLE; - boolean nextIsVisible = mNextImageView.getVisibility() == View.VISIBLE; - - if (showPrev && !prevIsVisible) { - Animation a = mShowPrevImageViewAnimation; - a.setDuration(500); - mPrevImageView.startAnimation(a); - mPrevImageView.setVisibility(View.VISIBLE); - } else if (!showPrev && prevIsVisible) { - Animation a = mHidePrevImageViewAnimation; - a.setDuration(500); - mPrevImageView.startAnimation(a); - mPrevImageView.setVisibility(View.GONE); - } - - if (showNext && !nextIsVisible) { - Animation a = mShowNextImageViewAnimation; - a.setDuration(500); - mNextImageView.startAnimation(a); - mNextImageView.setVisibility(View.VISIBLE); - } else if (!showNext && nextIsVisible) { - Animation a = mHideNextImageViewAnimation; - a.setDuration(500); - mNextImageView.startAnimation(a); - mNextImageView.setVisibility(View.GONE); - } - } - - private void hideOnScreenControls() { - if (mShowActionIcons - && mActionIconPanel.getVisibility() == View.VISIBLE) { - Animation animation = new AlphaAnimation(1, 0); - animation.setDuration(500); - mActionIconPanel.startAnimation(animation); - mActionIconPanel.setVisibility(View.INVISIBLE); - } - - if (mNextImageView.getVisibility() == View.VISIBLE) { - Animation a = mHideNextImageViewAnimation; - a.setDuration(500); - mNextImageView.startAnimation(a); - mNextImageView.setVisibility(View.INVISIBLE); - } - - if (mPrevImageView.getVisibility() == View.VISIBLE) { - Animation a = mHidePrevImageViewAnimation; - a.setDuration(500); - mPrevImageView.startAnimation(a); - mPrevImageView.setVisibility(View.INVISIBLE); - } - - mZoomButtonsController.setVisible(false); - } - - private void showOnScreenControls() { - if (mPaused) return; - // If the view has not been attached to the window yet, the - // zoomButtonControls will not able to show up. So delay it until the - // view has attached to window. - if (mActionIconPanel.getWindowToken() == null) { - mHandler.postGetterCallback(new Runnable() { - public void run() { - showOnScreenControls(); - } - }); - return; - } - updateNextPrevControls(); - - IImage image = mAllImages.getImageAt(mCurrentPosition); - if (image instanceof VideoObject) { - mZoomButtonsController.setVisible(false); - } else { - updateZoomButtonsEnabled(); - mZoomButtonsController.setVisible(true); - } - - if (mShowActionIcons - && mActionIconPanel.getVisibility() != View.VISIBLE) { - Animation animation = new AlphaAnimation(0, 1); - animation.setDuration(500); - mActionIconPanel.startAnimation(animation); - mActionIconPanel.setVisibility(View.VISIBLE); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - if (mPaused) return true; - if (mZoomButtonsController.isVisible()) { - scheduleDismissOnScreenControls(); - } - return super.dispatchTouchEvent(m); - } - - private void updateZoomButtonsEnabled() { - ImageViewTouch imageView = mImageView; - float scale = imageView.getScale(); - mZoomButtonsController.setZoomInEnabled(scale < imageView.mMaxZoom); - mZoomButtonsController.setZoomOutEnabled(scale > 1); - } - - @Override - protected void onDestroy() { - // This is necessary to make the ZoomButtonsController unregister - // its configuration change receiver. - if (mZoomButtonsController != null) { - mZoomButtonsController.setVisible(false); - } - super.onDestroy(); - } - - private void scheduleDismissOnScreenControls() { - mHandler.removeCallbacks(mDismissOnScreenControlRunner); - mHandler.postDelayed(mDismissOnScreenControlRunner, 2000); - } - - private void setupOnScreenControls(View rootView, View ownerView) { - mNextImageView = rootView.findViewById(R.id.next_image); - mPrevImageView = rootView.findViewById(R.id.prev_image); - - mNextImageView.setOnClickListener(this); - mPrevImageView.setOnClickListener(this); - - setupZoomButtonController(ownerView); - setupOnTouchListeners(rootView); - } - - private void setupZoomButtonController(final View ownerView) { - mZoomButtonsController = new ZoomButtonsController(ownerView); - mZoomButtonsController.setAutoDismissed(false); - mZoomButtonsController.setZoomSpeed(100); - mZoomButtonsController.setOnZoomListener( - new ZoomButtonsController.OnZoomListener() { - public void onVisibilityChanged(boolean visible) { - if (visible) { - updateZoomButtonsEnabled(); - } - } - - public void onZoom(boolean zoomIn) { - if (zoomIn) { - mImageView.zoomIn(); - } else { - mImageView.zoomOut(); - } - mZoomButtonsController.setVisible(true); - updateZoomButtonsEnabled(); - } - }); - } - - private void setupOnTouchListeners(View rootView) { - mGestureDetector = new GestureDetector(this, new MyGestureListener()); - - // If the user touches anywhere on the panel (including the - // next/prev button). We show the on-screen controls. In addition - // to that, if the touch is not on the prev/next button, we - // pass the event to the gesture detector to detect double tap. - final OnTouchListener buttonListener = new OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - scheduleDismissOnScreenControls(); - return false; - } - }; - - OnTouchListener rootListener = new OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - buttonListener.onTouch(v, event); - mGestureDetector.onTouchEvent(event); - - // We do not use the return value of - // mGestureDetector.onTouchEvent because we will not receive - // the "up" event if we return false for the "down" event. - return true; - } - }; - - mNextImageView.setOnTouchListener(buttonListener); - mPrevImageView.setOnTouchListener(buttonListener); - rootView.setOnTouchListener(rootListener); - } - - private class MyGestureListener extends - GestureDetector.SimpleOnGestureListener { - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - if (mPaused) return false; - ImageViewTouch imageView = mImageView; - if (imageView.getScale() > 1F) { - imageView.postTranslateCenter(-distanceX, -distanceY); - } - return true; - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - if (mPaused) return false; - setMode(MODE_NORMAL); - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (mPaused) return false; - showOnScreenControls(); - scheduleDismissOnScreenControls(); - return true; - } - - @Override - public boolean onDoubleTap(MotionEvent e) { - if (mPaused) return false; - ImageViewTouch imageView = mImageView; - - // Switch between the original scale and 3x scale. - if (imageView.getScale() > 2F) { - mImageView.zoomTo(1f); - } else { - mImageView.zoomToPoint(3f, e.getX(), e.getY()); - } - return true; - } - } - - boolean isPickIntent() { - String action = getIntent().getAction(); - return (Intent.ACTION_PICK.equals(action) - || Intent.ACTION_GET_CONTENT.equals(action)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem item = menu.add(Menu.NONE, Menu.NONE, - MenuHelper.POSITION_SLIDESHOW, - R.string.slide_show); - item.setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - setMode(MODE_SLIDESHOW); - mLastSlideShowImage = mCurrentPosition; - loadNextImage(mCurrentPosition, 0, true); - return true; - } - }); - item.setIcon(android.R.drawable.ic_menu_slideshow); - - mImageMenuRunnable = MenuHelper.addImageMenuItems( - menu, - MenuHelper.INCLUDE_ALL, - ViewImage.this, - mHandler, - mDeletePhotoRunnable, - new MenuHelper.MenuInvoker() { - public void run(final MenuHelper.MenuCallback cb) { - if (mPaused) return; - setMode(MODE_NORMAL); - - IImage image = mAllImages.getImageAt(mCurrentPosition); - Uri uri = image.fullSizeImageUri(); - cb.run(uri, image); - - // We might have deleted all images in the callback, so - // call setImage() only if we still have some images. - if (mAllImages.getCount() > 0) { - mImageView.clear(); - setImage(mCurrentPosition, false); - } - } - }); - - item = menu.add(Menu.NONE, Menu.NONE, - MenuHelper.POSITION_GALLERY_SETTING, R.string.camerasettings); - item.setOnMenuItemClickListener( - new MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Intent preferences = new Intent(); - preferences.setClass(ViewImage.this, GallerySettings.class); - startActivity(preferences); - return true; - } - }); - item.setAlphabeticShortcut('p'); - item.setIcon(android.R.drawable.ic_menu_preferences); - - return true; - } - - protected Runnable mDeletePhotoRunnable = new Runnable() { - public void run() { - mAllImages.removeImageAt(mCurrentPosition); - if (mAllImages.getCount() == 0) { - finish(); - return; - } else { - if (mCurrentPosition == mAllImages.getCount()) { - mCurrentPosition -= 1; - } - } - mImageView.clear(); - mCache.clear(); // Because the position number is changed. - setImage(mCurrentPosition, true); - } - }; - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - - super.onPrepareOptionsMenu(menu); - if (mPaused) return false; - - setMode(MODE_NORMAL); - IImage image = mAllImages.getImageAt(mCurrentPosition); - - if (mImageMenuRunnable != null) { - mImageMenuRunnable.gettingReadyToOpen(menu, image); - } - - Uri uri = mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri(); - MenuHelper.enableShareMenuItem(menu, MenuHelper.isWhiteListUri(uri)); - - MenuHelper.enableShowOnMapMenuItem(menu, MenuHelper.hasLatLngData(image)); - - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - boolean b = super.onMenuItemSelected(featureId, item); - if (mImageMenuRunnable != null) { - mImageMenuRunnable.aboutToCall(item, - mAllImages.getImageAt(mCurrentPosition)); - } - return b; - } - - void setImage(int pos, boolean showControls) { - mCurrentPosition = pos; - - Bitmap b = mCache.getBitmap(pos); - if (b != null) { - IImage image = mAllImages.getImageAt(pos); - mImageView.setImageRotateBitmapResetBase( - new RotateBitmap(b, image.getDegreesRotated()), true); - updateZoomButtonsEnabled(); - } - - ImageGetterCallback cb = new ImageGetterCallback() { - public void completed() { - } - - public boolean wantsThumbnail(int pos, int offset) { - return !mCache.hasBitmap(pos + offset); - } - - public boolean wantsFullImage(int pos, int offset) { - return offset == 0; - } - - public int fullImageSizeToUse(int pos, int offset) { - // this number should be bigger so that we can zoom. we may - // need to get fancier and read in the fuller size image as the - // user starts to zoom. - // Originally the value is set to 480 in order to avoid OOM. - // Now we set it to 2048 because of using - // native memory allocation for Bitmaps. - final int imageViewSize = 2048; - return imageViewSize; - } - - public int [] loadOrder() { - return sOrderAdjacents; - } - - public void imageLoaded(int pos, int offset, RotateBitmap bitmap, - boolean isThumb) { - // shouldn't get here after onPause() - - // We may get a result from a previous request. Ignore it. - if (pos != mCurrentPosition) { - bitmap.recycle(); - return; - } - - if (isThumb) { - mCache.put(pos + offset, bitmap.getBitmap()); - } - if (offset == 0) { - // isThumb: We always load thumb bitmap first, so we will - // reset the supp matrix for then thumb bitmap, and keep - // the supp matrix when the full bitmap is loaded. - mImageView.setImageRotateBitmapResetBase(bitmap, isThumb); - updateZoomButtonsEnabled(); - } - } - }; - - // Could be null if we're stopping a slide show in the course of pausing - if (mGetter != null) { - mGetter.setPosition(pos, cb, mAllImages, mHandler); - } - updateActionIcons(); - if (showControls) showOnScreenControls(); - scheduleDismissOnScreenControls(); - } - - @Override - public void onCreate(Bundle instanceState) { - super.onCreate(instanceState); - - Intent intent = getIntent(); - mFullScreenInNormalMode = intent.getBooleanExtra( - MediaStore.EXTRA_FULL_SCREEN, true); - mShowActionIcons = intent.getBooleanExtra( - MediaStore.EXTRA_SHOW_ACTION_ICONS, true); - - mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - - setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.viewimage); - - mImageView = (ImageViewTouch) findViewById(R.id.image); - mImageView.setEnableTrackballScroll(true); - mCache = new BitmapCache(3); - mImageView.setRecycler(mCache); - - makeGetter(); - - mAnimationIndex = -1; - - mSlideShowInAnimation = new Animation[] { - makeInAnimation(R.anim.transition_in), - makeInAnimation(R.anim.slide_in), - makeInAnimation(R.anim.slide_in_vertical), - }; - - mSlideShowOutAnimation = new Animation[] { - makeOutAnimation(R.anim.transition_out), - makeOutAnimation(R.anim.slide_out), - makeOutAnimation(R.anim.slide_out_vertical), - }; - - mSlideShowImageViews[0] = - (ImageViewTouchBase) findViewById(R.id.image1_slideShow); - mSlideShowImageViews[1] = - (ImageViewTouchBase) findViewById(R.id.image2_slideShow); - for (ImageViewTouchBase v : mSlideShowImageViews) { - v.setVisibility(View.INVISIBLE); - v.setRecycler(mCache); - } - - mActionIconPanel = findViewById(R.id.action_icon_panel); - - mParam = getIntent().getParcelableExtra(KEY_IMAGE_LIST); - - boolean slideshow; - if (instanceState != null) { - mSavedUri = instanceState.getParcelable(STATE_URI); - slideshow = instanceState.getBoolean(STATE_SLIDESHOW, false); - mShowControls = instanceState.getBoolean(STATE_SHOW_CONTROLS, true); - } else { - mSavedUri = getIntent().getData(); - slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false); - } - - // We only show action icons for URIs that we know we can share and - // delete. Although we get read permission (for the images) from - // applications like MMS, we cannot pass the permission to other - // activities due to the current framework design. - if (!MenuHelper.isWhiteListUri(mSavedUri)) { - mShowActionIcons = false; - } - - if (mShowActionIcons) { - int[] pickIds = {R.id.attach, R.id.cancel}; - int[] normalIds = {R.id.setas, R.id.play, R.id.share, R.id.discard}; - int[] connectIds = isPickIntent() ? pickIds : normalIds; - for (int id : connectIds) { - View view = mActionIconPanel.findViewById(id); - view.setVisibility(View.VISIBLE); - view.setOnClickListener(this); - } - } - - // Don't show the "delete" icon for SingleImageList. - if (ImageManager.isSingleImageMode(mSavedUri.toString())) { - mActionIconPanel.findViewById(R.id.discard) - .setVisibility(View.GONE); - } - - if (slideshow) { - setMode(MODE_SLIDESHOW); - } else { - if (mFullScreenInNormalMode) { - getWindow().addFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - if (mShowActionIcons) { - mActionIconPanel.setVisibility(View.VISIBLE); - } - } - - setupOnScreenControls(findViewById(R.id.rootLayout), mImageView); - } - - private void updateActionIcons() { - if (isPickIntent()) return; - - IImage image = mAllImages.getImageAt(mCurrentPosition); - View panel = mActionIconPanel; - if (image instanceof VideoObject) { - panel.findViewById(R.id.setas).setVisibility(View.GONE); - panel.findViewById(R.id.play).setVisibility(View.VISIBLE); - } else { - panel.findViewById(R.id.setas).setVisibility(View.VISIBLE); - panel.findViewById(R.id.play).setVisibility(View.GONE); - } - } - - private Animation makeInAnimation(int id) { - Animation inAnimation = AnimationUtils.loadAnimation(this, id); - return inAnimation; - } - - private Animation makeOutAnimation(int id) { - Animation outAnimation = AnimationUtils.loadAnimation(this, id); - return outAnimation; - } - - private static int getPreferencesInteger( - SharedPreferences prefs, String key, int defaultValue) { - String value = prefs.getString(key, null); - try { - return value == null ? defaultValue : Integer.parseInt(value); - } catch (NumberFormatException ex) { - Log.e(TAG, "couldn't parse preference: " + value, ex); - return defaultValue; - } - } - - void setMode(int mode) { - if (mMode == mode) { - return; - } - View slideshowPanel = findViewById(R.id.slideShowContainer); - View normalPanel = findViewById(R.id.abs); - - Window win = getWindow(); - mMode = mode; - if (mode == MODE_SLIDESHOW) { - slideshowPanel.setVisibility(View.VISIBLE); - normalPanel.setVisibility(View.GONE); - - win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN - | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - mImageView.clear(); - mActionIconPanel.setVisibility(View.GONE); - - slideshowPanel.getRootView().requestLayout(); - - // The preferences we want to read: - // mUseShuffleOrder - // mSlideShowLoop - // mAnimationIndex - // mSlideShowInterval - - mUseShuffleOrder = mPrefs.getBoolean(PREF_SHUFFLE_SLIDESHOW, false); - mSlideShowLoop = mPrefs.getBoolean(PREF_SLIDESHOW_REPEAT, false); - mAnimationIndex = getPreferencesInteger( - mPrefs, "pref_gallery_slideshow_transition_key", 0); - mSlideShowInterval = getPreferencesInteger( - mPrefs, "pref_gallery_slideshow_interval_key", 3) * 1000; - } else { - slideshowPanel.setVisibility(View.GONE); - normalPanel.setVisibility(View.VISIBLE); - - win.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - if (mFullScreenInNormalMode) { - win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } else { - win.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - if (mGetter != null) { - mGetter.cancelCurrent(); - } - - if (mShowActionIcons) { - Animation animation = new AlphaAnimation(0F, 1F); - animation.setDuration(500); - mActionIconPanel.setAnimation(animation); - mActionIconPanel.setVisibility(View.VISIBLE); - } - - ImageViewTouchBase dst = mImageView; - dst.mLastXTouchPos = -1; - dst.mLastYTouchPos = -1; - - for (ImageViewTouchBase ivt : mSlideShowImageViews) { - ivt.clear(); - } - - mShuffleOrder = null; - - // mGetter null is a proxy for being paused - if (mGetter != null) { - setImage(mCurrentPosition, true); - } - } - } - - private void generateShuffleOrder() { - if (mShuffleOrder == null - || mShuffleOrder.length != mAllImages.getCount()) { - mShuffleOrder = new int[mAllImages.getCount()]; - for (int i = 0, n = mShuffleOrder.length; i < n; i++) { - mShuffleOrder[i] = i; - } - } - - for (int i = mShuffleOrder.length - 1; i >= 0; i--) { - int r = mRandom.nextInt(i + 1); - if (r != i) { - int tmp = mShuffleOrder[r]; - mShuffleOrder[r] = mShuffleOrder[i]; - mShuffleOrder[i] = tmp; - } - } - } - - private void loadNextImage(final int requestedPos, final long delay, - final boolean firstCall) { - if (firstCall && mUseShuffleOrder) { - generateShuffleOrder(); - } - - final long targetDisplayTime = System.currentTimeMillis() + delay; - - ImageGetterCallback cb = new ImageGetterCallback() { - public void completed() { - } - - public boolean wantsThumbnail(int pos, int offset) { - return true; - } - - public boolean wantsFullImage(int pos, int offset) { - return false; - } - - public int [] loadOrder() { - return sOrderSlideshow; - } - - public int fullImageSizeToUse(int pos, int offset) { - return 480; // TODO compute this - } - - public void imageLoaded(final int pos, final int offset, - final RotateBitmap bitmap, final boolean isThumb) { - long timeRemaining = Math.max(0, - targetDisplayTime - System.currentTimeMillis()); - mHandler.postDelayedGetterCallback(new Runnable() { - public void run() { - if (mMode == MODE_NORMAL) { - return; - } - - ImageViewTouchBase oldView = - mSlideShowImageViews[mSlideShowImageCurrent]; - - if (++mSlideShowImageCurrent - == mSlideShowImageViews.length) { - mSlideShowImageCurrent = 0; - } - - ImageViewTouchBase newView = - mSlideShowImageViews[mSlideShowImageCurrent]; - newView.setVisibility(View.VISIBLE); - newView.setImageRotateBitmapResetBase(bitmap, true); - newView.bringToFront(); - - int animation = 0; - - if (mAnimationIndex == -1) { - int n = mRandom.nextInt( - mSlideShowInAnimation.length); - animation = n; - } else { - animation = mAnimationIndex; - } - - Animation aIn = mSlideShowInAnimation[animation]; - newView.startAnimation(aIn); - newView.setVisibility(View.VISIBLE); - - Animation aOut = mSlideShowOutAnimation[animation]; - oldView.setVisibility(View.INVISIBLE); - oldView.startAnimation(aOut); - - mCurrentPosition = requestedPos; - - if (mCurrentPosition == mLastSlideShowImage - && !firstCall) { - if (mSlideShowLoop) { - if (mUseShuffleOrder) { - generateShuffleOrder(); - } - } else { - setMode(MODE_NORMAL); - return; - } - } - - loadNextImage( - (mCurrentPosition + 1) % mAllImages.getCount(), - mSlideShowInterval, false); - } - }, timeRemaining); - } - }; - // Could be null if we're stopping a slide show in the course of pausing - if (mGetter != null) { - int pos = requestedPos; - if (mShuffleOrder != null) { - pos = mShuffleOrder[pos]; - } - mGetter.setPosition(pos, cb, mAllImages, mHandler); - } - } - - private void makeGetter() { - mGetter = new ImageGetter(getContentResolver()); - } - - private IImageList buildImageListFromUri(Uri uri) { - String sortOrder = mPrefs.getString( - "pref_gallery_sort_key", "descending"); - int sort = sortOrder.equals("ascending") - ? ImageManager.SORT_ASCENDING - : ImageManager.SORT_DESCENDING; - return ImageManager.makeImageList(getContentResolver(), uri, sort); - } - - private boolean init(Uri uri) { - if (uri == null) return false; - mAllImages = (mParam == null) - ? buildImageListFromUri(uri) - : ImageManager.makeImageList(getContentResolver(), mParam); - IImage image = mAllImages.getImageForUri(uri); - if (image == null) return false; - mCurrentPosition = mAllImages.getImageIndex(image); - mLastSlideShowImage = mCurrentPosition; - return true; - } - - private Uri getCurrentUri() { - if (mAllImages.getCount() == 0) return null; - IImage image = mAllImages.getImageAt(mCurrentPosition); - if (image == null) return null; - return image.fullSizeImageUri(); - } - - @Override - public void onSaveInstanceState(Bundle b) { - super.onSaveInstanceState(b); - b.putParcelable(STATE_URI, - mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri()); - b.putBoolean(STATE_SLIDESHOW, mMode == MODE_SLIDESHOW); - } - - @Override - public void onStart() { - super.onStart(); - mPaused = false; - - if (!init(mSavedUri)) { - Log.w(TAG, "init failed: " + mSavedUri); - finish(); - return; - } - - // normally this will never be zero but if one "backs" into this - // activity after removing the sdcard it could be zero. in that - // case just "finish" since there's nothing useful that can happen. - int count = mAllImages.getCount(); - if (count == 0) { - finish(); - return; - } else if (count <= mCurrentPosition) { - mCurrentPosition = count - 1; - } - - if (mGetter == null) { - makeGetter(); - } - - if (mMode == MODE_SLIDESHOW) { - loadNextImage(mCurrentPosition, 0, true); - } else { // MODE_NORMAL - setImage(mCurrentPosition, mShowControls); - mShowControls = false; - } - } - - @Override - public void onStop() { - super.onStop(); - mPaused = true; - - // mGetter could be null if we call finish() and leave early in - // onStart(). - if (mGetter != null) { - mGetter.cancelCurrent(); - mGetter.stop(); - mGetter = null; - } - setMode(MODE_NORMAL); - - // removing all callback in the message queue - mHandler.removeAllGetterCallbacks(); - - if (mAllImages != null) { - mSavedUri = getCurrentUri(); - mAllImages.close(); - mAllImages = null; - } - - hideOnScreenControls(); - mImageView.clear(); - mCache.clear(); - - for (ImageViewTouchBase iv : mSlideShowImageViews) { - iv.clear(); - } - } - - private void startShareMediaActivity(IImage image) { - boolean isVideo = image instanceof VideoObject; - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType(image.getMimeType()); - intent.putExtra(Intent.EXTRA_STREAM, image.fullSizeImageUri()); - try { - startActivity(Intent.createChooser(intent, getText( - isVideo ? R.string.sendVideo : R.string.sendImage))); - } catch (android.content.ActivityNotFoundException ex) { - Toast.makeText(this, isVideo - ? R.string.no_way_to_share_image - : R.string.no_way_to_share_video, - Toast.LENGTH_SHORT).show(); - } - } - - private void startPlayVideoActivity() { - IImage image = mAllImages.getImageAt(mCurrentPosition); - Intent intent = new Intent( - Intent.ACTION_VIEW, image.fullSizeImageUri()); - try { - startActivity(intent); - } catch (android.content.ActivityNotFoundException ex) { - Log.e(TAG, "Couldn't view video " + image.fullSizeImageUri(), ex); - } - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.discard: - MenuHelper.deletePhoto(this, mDeletePhotoRunnable); - break; - case R.id.play: - startPlayVideoActivity(); - break; - case R.id.share: { - IImage image = mAllImages.getImageAt(mCurrentPosition); - if (!MenuHelper.isWhiteListUri(image.fullSizeImageUri())) { - return; - } - startShareMediaActivity(image); - break; - } - case R.id.setas: { - IImage image = mAllImages.getImageAt(mCurrentPosition); - Intent intent = Util.createSetAsIntent(image); - try { - startActivity(Intent.createChooser( - intent, getText(R.string.setImage))); - } catch (android.content.ActivityNotFoundException ex) { - Toast.makeText(this, R.string.no_way_to_share_video, - Toast.LENGTH_SHORT).show(); - } - break; - } - case R.id.next_image: - moveNextOrPrevious(1); - break; - case R.id.prev_image: - moveNextOrPrevious(-1); - break; - } - } - - private void moveNextOrPrevious(int delta) { - int nextImagePos = mCurrentPosition + delta; - if ((0 <= nextImagePos) && (nextImagePos < mAllImages.getCount())) { - setImage(nextImagePos, true); - showOnScreenControls(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - switch (requestCode) { - case MenuHelper.RESULT_COMMON_MENU_CROP: - if (resultCode == RESULT_OK) { - // The CropImage activity passes back the Uri of the - // cropped image as the Action rather than the Data. - mSavedUri = Uri.parse(data.getAction()); - - // if onStart() runs before, then set the returned - // image as currentImage. - if (mAllImages != null) { - IImage image = mAllImages.getImageForUri(mSavedUri); - // image could be null if SD card is removed. - if (image == null) { - finish(); - } else { - mCurrentPosition = mAllImages.getImageIndex(image); - setImage(mCurrentPosition, false); - } - } - } - break; - } - } -} - -class ImageViewTouch extends ImageViewTouchBase { - private final ViewImage mViewImage; - private boolean mEnableTrackballScroll; - - public ImageViewTouch(Context context) { - super(context); - mViewImage = (ViewImage) context; - } - - public ImageViewTouch(Context context, AttributeSet attrs) { - super(context, attrs); - mViewImage = (ViewImage) context; - } - - public void setEnableTrackballScroll(boolean enable) { - mEnableTrackballScroll = enable; - } - - protected void postTranslateCenter(float dx, float dy) { - super.postTranslate(dx, dy); - center(true, true); - } - - private static final float PAN_RATE = 20; - - // This is the time we allow the dpad to change the image position again. - private long mNextChangePositionTime; - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mViewImage.mPaused) return false; - - // Don't respond to arrow keys if trackball scrolling is not enabled - if (!mEnableTrackballScroll) { - if ((keyCode >= KeyEvent.KEYCODE_DPAD_UP) - && (keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT)) { - return super.onKeyDown(keyCode, event); - } - } - - int current = mViewImage.mCurrentPosition; - - int nextImagePos = -2; // default no next image - try { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_CENTER: { - if (mViewImage.isPickIntent()) { - IImage img = mViewImage.mAllImages - .getImageAt(mViewImage.mCurrentPosition); - mViewImage.setResult(ViewImage.RESULT_OK, - new Intent().setData(img.fullSizeImageUri())); - mViewImage.finish(); - } - break; - } - case KeyEvent.KEYCODE_DPAD_LEFT: { - if (getScale() <= 1F && event.getEventTime() - >= mNextChangePositionTime) { - nextImagePos = current - 1; - mNextChangePositionTime = event.getEventTime() + 500; - } else { - panBy(PAN_RATE, 0); - center(true, false); - } - return true; - } - case KeyEvent.KEYCODE_DPAD_RIGHT: { - if (getScale() <= 1F && event.getEventTime() - >= mNextChangePositionTime) { - nextImagePos = current + 1; - mNextChangePositionTime = event.getEventTime() + 500; - } else { - panBy(-PAN_RATE, 0); - center(true, false); - } - return true; - } - case KeyEvent.KEYCODE_DPAD_UP: { - panBy(0, PAN_RATE); - center(false, true); - return true; - } - case KeyEvent.KEYCODE_DPAD_DOWN: { - panBy(0, -PAN_RATE); - center(false, true); - return true; - } - case KeyEvent.KEYCODE_DEL: - MenuHelper.deletePhoto( - mViewImage, mViewImage.mDeletePhotoRunnable); - break; - } - } finally { - if (nextImagePos >= 0 - && nextImagePos < mViewImage.mAllImages.getCount()) { - synchronized (mViewImage) { - mViewImage.setMode(ViewImage.MODE_NORMAL); - mViewImage.setImage(nextImagePos, true); - } - } else if (nextImagePos != -2) { - center(true, true); - } - } - - return super.onKeyDown(keyCode, event); - } -} - -// This is a cache for Bitmap displayed in ViewImage (normal mode, thumb only). -class BitmapCache implements ImageViewTouchBase.Recycler { - public static class Entry { - int mPos; - Bitmap mBitmap; - public Entry() { - clear(); - } - public void clear() { - mPos = -1; - mBitmap = null; - } - } - - private final Entry[] mCache; - - public BitmapCache(int size) { - mCache = new Entry[size]; - for (int i = 0; i < mCache.length; i++) { - mCache[i] = new Entry(); - } - } - - // Given the position, find the associated entry. Returns null if there is - // no such entry. - private Entry findEntry(int pos) { - for (Entry e : mCache) { - if (pos == e.mPos) { - return e; - } - } - return null; - } - - // Returns the thumb bitmap if we have it, otherwise return null. - public synchronized Bitmap getBitmap(int pos) { - Entry e = findEntry(pos); - if (e != null) { - return e.mBitmap; - } - return null; - } - - public synchronized void put(int pos, Bitmap bitmap) { - // First see if we already have this entry. - if (findEntry(pos) != null) { - return; - } - - // Find the best entry we should replace. - // See if there is any empty entry. - // Otherwise assuming sequential access, kick out the entry with the - // greatest distance. - Entry best = null; - int maxDist = -1; - for (Entry e : mCache) { - if (e.mPos == -1) { - best = e; - break; - } else { - int dist = Math.abs(pos - e.mPos); - if (dist > maxDist) { - maxDist = dist; - best = e; - } - } - } - - // Recycle the image being kicked out. - // This only works because our current usage is sequential, so we - // do not happen to recycle the image being displayed. - if (best.mBitmap != null) { - best.mBitmap.recycle(); - } - - best.mPos = pos; - best.mBitmap = bitmap; - } - - // Recycle all bitmaps in the cache and clear the cache. - public synchronized void clear() { - for (Entry e : mCache) { - if (e.mBitmap != null) { - e.mBitmap.recycle(); - } - e.clear(); - } - } - - // Returns whether the bitmap is in the cache. - public synchronized boolean hasBitmap(int pos) { - Entry e = findEntry(pos); - return (e != null); - } - - // Recycle the bitmap if it's not in the cache. - // The input must be non-null. - public synchronized void recycle(Bitmap b) { - for (Entry e : mCache) { - if (e.mPos != -1) { - if (e.mBitmap == b) { - return; - } - } - } - b.recycle(); - } -} diff --git a/src/com/android/camera/Wallpaper.java b/src/com/android/camera/Wallpaper.java deleted file mode 100644 index a715958a..00000000 --- a/src/com/android/camera/Wallpaper.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.content.Intent; -import android.net.Uri; -import android.os.Bundle; - -/** - * Wallpaper picker for the camera application. This just redirects to the - * standard pick action. - */ -public class Wallpaper extends NoSearchActivity { - @SuppressWarnings("unused") - private static final String TAG = "Wallpaper"; - private static final int PHOTO_PICKED = 1; - private static final int CROP_DONE = 2; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - Uri imageToUse = getIntent().getData(); - if (imageToUse != null) { - Intent intent = new Intent(); - intent.setClassName("com.android.camera", - "com.android.camera.CropImage"); - intent.setData(imageToUse); - formatIntent(intent); - startActivityForResult(intent, CROP_DONE); - } else { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); - intent.setType("image/*"); - intent.putExtra("crop", "true"); - formatIntent(intent); - startActivityForResult(intent, PHOTO_PICKED); - } - } - - protected void formatIntent(Intent intent) { - int width = getWallpaperDesiredMinimumWidth(); - int height = getWallpaperDesiredMinimumHeight(); - intent.putExtra("outputX", width); - intent.putExtra("outputY", height); - intent.putExtra("aspectX", width); - intent.putExtra("aspectY", height); - intent.putExtra("scale", true); - intent.putExtra("noFaceDetection", true); - intent.putExtra("setWallpaper", true); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - if ((requestCode == PHOTO_PICKED || requestCode == CROP_DONE)) { - setResult(resultCode); - finish(); - } - } -} diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java index 6e2f8f1a..42d0f66d 100644 --- a/src/com/android/camera/gallery/BaseImage.java +++ b/src/com/android/camera/gallery/BaseImage.java @@ -117,10 +117,6 @@ public abstract class BaseImage implements IImage { } } - public long fullSizeImageId() { - return mId; - } - public Uri fullSizeImageUri() { return mUri; } diff --git a/src/com/android/camera/gallery/IImage.java b/src/com/android/camera/gallery/IImage.java index bad41ccc..8b443d6d 100644 --- a/src/com/android/camera/gallery/IImage.java +++ b/src/com/android/camera/gallery/IImage.java @@ -47,7 +47,6 @@ public interface IImage { /** Get the input stream associated with a given full size image. */ public abstract InputStream fullSizeImageData(); - public abstract long fullSizeImageId(); public abstract Uri fullSizeImageUri(); /** Get the path of the (full size) image data. */ diff --git a/src/com/android/camera/gallery/IImageList.java b/src/com/android/camera/gallery/IImageList.java index 07a6bb28..6ea1be06 100644 --- a/src/com/android/camera/gallery/IImageList.java +++ b/src/com/android/camera/gallery/IImageList.java @@ -44,7 +44,6 @@ import java.util.HashMap; * The interface of all image collections used in gallery. */ public interface IImageList { - public HashMap<String, String> getBucketIds(); /** * Returns the count of image objects. diff --git a/src/com/android/camera/gallery/ImageList.java b/src/com/android/camera/gallery/ImageList.java index 9a47e55b..3dee3d16 100644 --- a/src/com/android/camera/gallery/ImageList.java +++ b/src/com/android/camera/gallery/ImageList.java @@ -35,26 +35,6 @@ public class ImageList extends BaseImageList implements IImageList { private static final String[] ACCEPTABLE_IMAGE_TYPES = new String[] { "image/jpeg", "image/png", "image/gif" }; - public HashMap<String, String> getBucketIds() { - Uri uri = mBaseUri.buildUpon() - .appendQueryParameter("distinct", "true").build(); - Cursor cursor = Media.query( - mContentResolver, uri, - new String[] { - Media.BUCKET_DISPLAY_NAME, - Media.BUCKET_ID}, - whereClause(), whereClauseArgs(), null); - try { - HashMap<String, String> hash = new HashMap<String, String>(); - while (cursor.moveToNext()) { - hash.put(cursor.getString(1), cursor.getString(0)); - } - return hash; - } finally { - cursor.close(); - } - } - /** * ImageList constructor. */ diff --git a/src/com/android/camera/gallery/ImageListUber.java b/src/com/android/camera/gallery/ImageListUber.java index 95146ae3..85f93375 100644 --- a/src/com/android/camera/gallery/ImageListUber.java +++ b/src/com/android/camera/gallery/ImageListUber.java @@ -68,14 +68,6 @@ public class ImageListUber implements IImageList { } } - public HashMap<String, String> getBucketIds() { - HashMap<String, String> hashMap = new HashMap<String, String>(); - for (IImageList list : mSubList) { - hashMap.putAll(list.getBucketIds()); - } - return hashMap; - } - public int getCount() { int count = 0; for (IImageList subList : mSubList) { diff --git a/src/com/android/camera/gallery/SingleImageList.java b/src/com/android/camera/gallery/SingleImageList.java index 8abb306f..7963cf85 100644 --- a/src/com/android/camera/gallery/SingleImageList.java +++ b/src/com/android/camera/gallery/SingleImageList.java @@ -38,10 +38,6 @@ public class SingleImageList implements IImageList { mSingleImage = new UriImage(this, resolver, uri); } - public HashMap<String, String> getBucketIds() { - throw new UnsupportedOperationException(); - } - public int getCount() { return 1; } diff --git a/src/com/android/camera/gallery/UriImage.java b/src/com/android/camera/gallery/UriImage.java index 0db1633c..0f27b240 100644 --- a/src/com/android/camera/gallery/UriImage.java +++ b/src/com/android/camera/gallery/UriImage.java @@ -156,10 +156,6 @@ class UriImage implements IImage { return (options != null) ? options.outWidth : 0; } - public long fullSizeImageId() { - return 0; - } - public IImageList getContainer() { return mContainer; } diff --git a/src/com/android/camera/gallery/VideoList.java b/src/com/android/camera/gallery/VideoList.java index c22a206a..fc57baac 100644 --- a/src/com/android/camera/gallery/VideoList.java +++ b/src/com/android/camera/gallery/VideoList.java @@ -79,27 +79,6 @@ public class VideoList extends BaseImageList { super(resolver, uri, sort, bucketId); } - public HashMap<String, String> getBucketIds() { - Uri uri = mBaseUri.buildUpon() - .appendQueryParameter("distinct", "true").build(); - Cursor c = Images.Media.query( - mContentResolver, uri, - new String[] { - Media.BUCKET_DISPLAY_NAME, - Media.BUCKET_ID - }, - whereClause(), whereClauseArgs(), sortOrder()); - try { - HashMap<String, String> hash = new HashMap<String, String>(); - while (c.moveToNext()) { - hash.put(c.getString(1), c.getString(0)); - } - return hash; - } finally { - c.close(); - } - } - protected String whereClause() { return mBucketId != null ? Images.Media.BUCKET_ID + " = '" + mBucketId + "'" diff --git a/src/com/android/camera/gallery/VideoObject.java b/src/com/android/camera/gallery/VideoObject.java index 589e42fc..d6e50606 100644 --- a/src/com/android/camera/gallery/VideoObject.java +++ b/src/com/android/camera/gallery/VideoObject.java @@ -79,11 +79,6 @@ public class VideoObject extends BaseImage implements IImage { } @Override - public long fullSizeImageId() { - return mId; - } - - @Override public int getHeight() { return 0; } @@ -125,4 +120,4 @@ public class VideoObject extends BaseImage implements IImage { public String toString() { return new StringBuilder("VideoObject").append(mId).toString(); } -}
\ No newline at end of file +} diff --git a/tests/src/com/android/camera/gallery/ImageListUberUnitTests.java b/tests/src/com/android/camera/gallery/ImageListUberUnitTests.java deleted file mode 100644 index 30487f29..00000000 --- a/tests/src/com/android/camera/gallery/ImageListUberUnitTests.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.android.camera.gallery; - -import com.android.camera.ImageManager; - -import android.test.AndroidTestCase; - -public class ImageListUberUnitTests extends AndroidTestCase { - - public void testTheOrderOfGetImageAt() { - MockImageList listA = new MockImageList(); - MockImageList listB = new MockImageList(); - listA.addImage(new MockImage(2, 2)); - listA.addImage(new MockImage(0, 0)); - listB.addImage(new MockImage(1, 1)); - ImageListUber uber = new ImageListUber( - new IImageList[] {listA, listB}, ImageManager.SORT_DESCENDING); - - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(1, uber.getImageAt(1).fullSizeImageId()); - assertEquals(0, uber.getImageAt(2).fullSizeImageId()); - uber.close(); - - uber = new ImageListUber( - new IImageList[] {listA, listB}, ImageManager.SORT_DESCENDING); - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(1, uber.getImageAt(1).fullSizeImageId()); - assertEquals(0, uber.getImageAt(2).fullSizeImageId()); - uber.close(); - } - - public void testTheOrderOfGetImageAtCaseTwo() { - MockImageList listA = new MockImageList(); - MockImageList listB = new MockImageList(); - listA.addImage(new MockImage(2, 2)); - listA.addImage(new MockImage(1, 1)); - listB.addImage(new MockImage(0, 0)); - ImageListUber uber = new ImageListUber( - new IImageList[] {listB, listA}, ImageManager.SORT_DESCENDING); - - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(1, uber.getImageAt(1).fullSizeImageId()); - assertEquals(0, uber.getImageAt(2).fullSizeImageId()); - uber.close(); - - uber = new ImageListUber( - new IImageList[] {listA, listB}, ImageManager.SORT_DESCENDING); - - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(1, uber.getImageAt(1).fullSizeImageId()); - assertEquals(0, uber.getImageAt(2).fullSizeImageId()); - uber.close(); - } - - public void testRemoveImage() { - MockImageList listA = new MockImageList(); - MockImageList listB = new MockImageList(); - MockImage target = new MockImage(1, 1); - listA.addImage(new MockImage(2, 2)); - listA.addImage(new MockImage(0, 0)); - listB.addImage(target); - ImageListUber uber = new ImageListUber( - new IImageList[] {listB, listA}, ImageManager.SORT_DESCENDING); - uber.removeImage(target); - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(0, uber.getImageAt(1).fullSizeImageId()); - - assertEquals(0, uber.getImageIndex(uber.getImageAt(0))); - assertEquals(1, uber.getImageIndex(uber.getImageAt(1))); - uber.close(); - } - - public void testRemoveImageAt() { - MockImageList listA = new MockImageList(); - MockImageList listB = new MockImageList(); - MockImage target = new MockImage(1, 1); - listA.addImage(new MockImage(2, 2)); - listA.addImage(new MockImage(0, 0)); - listB.addImage(target); - ImageListUber uber = new ImageListUber( - new IImageList[] {listB, listA}, ImageManager.SORT_DESCENDING); - uber.removeImageAt(1); - assertEquals(2, uber.getImageAt(0).fullSizeImageId()); - assertEquals(0, uber.getImageAt(1).fullSizeImageId()); - - assertEquals(0, uber.getImageIndex(uber.getImageAt(0))); - assertEquals(1, uber.getImageIndex(uber.getImageAt(1))); - uber.close(); - } -} |