diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-02 22:54:39 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-02 22:54:39 -0800 |
commit | 2ec6be554f06b2568eb38f7ea5ba4570b1ecfb8d (patch) | |
tree | 686e596cfb390df2da5091ef08830c985902bd39 /src | |
parent | c4ef8241b05b9266de77defcfdf1154f400c77f4 (diff) | |
download | LegacyCamera-2ec6be554f06b2568eb38f7ea5ba4570b1ecfb8d.zip LegacyCamera-2ec6be554f06b2568eb38f7ea5ba4570b1ecfb8d.tar.gz LegacyCamera-2ec6be554f06b2568eb38f7ea5ba4570b1ecfb8d.tar.bz2 |
auto import from //depot/cupcake/@137055
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/camera/Camera.java | 46 | ||||
-rwxr-xr-x | src/com/android/camera/ImageManager.java | 26 | ||||
-rw-r--r-- | src/com/android/camera/MenuHelper.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/MovieView.java | 88 | ||||
-rw-r--r-- | src/com/android/camera/PhotoGadgetBind.java | 73 | ||||
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 59 | ||||
-rw-r--r-- | src/com/android/camera/ViewImage.java | 156 |
7 files changed, 323 insertions, 133 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 04a30cf..d0eb1b3 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -258,7 +258,7 @@ public class Camera extends Activity implements View.OnClickListener, String action = intent.getAction(); if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { // SD card available - updateStorageHint(); + updateStorageHint(calculatePicturesRemaining()); } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED) || action.equals(Intent.ACTION_MEDIA_CHECKING)) { // SD card unavailable @@ -832,7 +832,7 @@ public class Camera extends Activity implements View.OnClickListener, loadServiceThread.join(); } catch (InterruptedException ex) { } - + ImageManager.ensureOSXCompatibleFolder(); } @@ -1355,6 +1355,40 @@ public class Camera extends Activity implements View.OnClickListener, } return mCameraDevice != null; } + + private boolean isLastPictureValid() { + boolean isValid = true; + if (mLastPictureUri == null) return false; + try { + mContentResolver.openFileDescriptor(mLastPictureUri, "r").close(); + } + catch (Exception ex) { + isValid = false; + Log.e(TAG, ex.toString()); + } + return isValid; + } + + private void updateLastImage() { + ImageManager.IImageList list = ImageManager.instance().allImages( + this, + mContentResolver, + dataLocation(), + ImageManager.INCLUDE_IMAGES, + ImageManager.SORT_ASCENDING, + ImageManager.CAMERA_IMAGE_BUCKET_ID); + int count = list.getCount(); + if (count > 0) { + ImageManager.IImage image = list.getImageAt(count-1); + mLastPictureUri = image.fullSizeImageUri(); + Log.v(TAG, "updateLastImage: count="+ count + + ", lastPictureUri="+mLastPictureUri); + setLastPictureThumb(image.miniThumbBitmap(), mLastPictureUri); + } else { + mLastPictureUri = null; + } + list.deactivate(); + } private void restartPreview() { VideoPreview surfaceView = mSurfaceView; @@ -1371,6 +1405,10 @@ public class Camera extends Activity implements View.OnClickListener, // let the user take a picture, and delete that file if needed to save the new photo. calculatePicturesRemaining(); + if (!isLastPictureValid()) { + updateLastImage(); + } + if (mShouldShowLastPictureButton) { mShouldShowLastPictureButton = false; mLastPictureButton.setVisibility(View.VISIBLE); @@ -1523,7 +1561,7 @@ public class Camera extends Activity implements View.OnClickListener, private void viewLastImage() { Uri targetUri = mLastPictureUri; - if (targetUri != null) { + if (targetUri != null && isLastPictureValid()) { targetUri = targetUri.buildUpon(). appendQueryParameter("bucketId", ImageManager.CAMERA_IMAGE_BUCKET_ID).build(); Intent intent = new Intent(Intent.ACTION_VIEW, targetUri); @@ -1538,6 +1576,8 @@ public class Camera extends Activity implements View.OnClickListener, } catch (android.content.ActivityNotFoundException ex) { // ignore. } + } else { + Log.e(TAG, "Can't view last image."); } } diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index cc76e83..99e5366 100755 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -1835,7 +1835,7 @@ public class ImageManager { if (mimeType.equals("image/png")) return Bitmap.CompressFormat.PNG; - else if (mimeType.equals("image/png")) + else if (mimeType.equals("image/gif")) return Bitmap.CompressFormat.PNG; return Bitmap.CompressFormat.JPEG; @@ -2130,8 +2130,8 @@ public class ImageManager { } - final static private String sWhereClause = "(" + Images.Media.MIME_TYPE + "=? or " + Images.Media.MIME_TYPE + "=?" + ")"; - final static private String[] sAcceptableImageTypes = new String[] { "image/jpeg", "image/png" }; + final static private String sWhereClause = "(" + Images.Media.MIME_TYPE + " in (?, ?, ?))"; + final static private String[] sAcceptableImageTypes = new String[] { "image/jpeg", "image/png", "image/gif" }; final static private String sMiniThumbIsNull = "mini_thumb_magic isnull"; private static final String[] IMAGE_PROJECTION = new String[] { @@ -2360,10 +2360,14 @@ public class ImageManager { if (VERBOSE) { Log.v(TAG, "A: got bitmap " + b + " with sampleSize " + options.inSampleSize + " took " + (t2-t1)); } - pfd.close(); - } catch (IOException ex) { - if (VERBOSE) Log.v(TAG, "got io exception " + ex); + } catch (OutOfMemoryError ex) { + if (VERBOSE) Log.v(TAG, "got oom exception " + ex); return null; + } finally { + try { + pfd.close(); + } catch (IOException ex) { + } } return b; } @@ -3193,10 +3197,14 @@ public class ImageManager { if (VERBOSE) { Log.v(TAG, "C: got bitmap " + b + " with sampleSize " + options.inSampleSize); } - pfdInput.close(); - } catch (IOException ex) { - if (VERBOSE) Log.v(TAG, "got io exception " + ex); + } catch (OutOfMemoryError ex) { + if (VERBOSE) Log.v(TAG, "got oom exception " + ex); return null; + } finally { + try { + pfdInput.close(); + } catch (IOException ex) { + } } return b; } diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java index ffb99ef..7148cd6 100644 --- a/src/com/android/camera/MenuHelper.java +++ b/src/com/android/camera/MenuHelper.java @@ -434,9 +434,11 @@ public class MenuHelper { public boolean onMenuItemClick(MenuItem item) { onInvoke.run(new MenuCallback() { public void run(Uri uri, IImage image) { - Intent intent = new Intent(Intent.ACTION_VIEW, - image.fullSizeImageUri()); - activity.startActivity(intent); + if (image != null) { + Intent intent = new Intent(Intent.ACTION_VIEW, + image.fullSizeImageUri()); + activity.startActivity(intent); + } }}); return true; } diff --git a/src/com/android/camera/MovieView.java b/src/com/android/camera/MovieView.java index 091cc28..bf0e6ca 100644 --- a/src/com/android/camera/MovieView.java +++ b/src/com/android/camera/MovieView.java @@ -127,37 +127,46 @@ public class MovieView extends Activity implements MediaPlayer.OnErrorListener, } } + 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() { - String scheme = mUri.getScheme(); - if ("content".equalsIgnoreCase(scheme)) { - String[] projection = new String[]{Video.VideoColumns.DURATION, - Video.VideoColumns.BOOKMARK}; - try { - Cursor cursor = getContentResolver().query(mUri, projection, null, null, null); - if (cursor != null) { - try { - if ( cursor.moveToFirst() ) { - int duration = getCursorInteger(cursor, 0); - int bookmark = getCursorInteger(cursor, 1); - final int ONE_MINUTE = 60 * 1000; - final int TWO_MINUTES = 2 * ONE_MINUTE; - final int FIVE_MINUTES = 5 * ONE_MINUTE; - if ((bookmark < TWO_MINUTES) - || (duration < FIVE_MINUTES) - || (bookmark > (duration - ONE_MINUTE))) { - return null; - } - - return new Integer(bookmark); + if (!uriSupportsBookmarks(mUri)) { + return null; + } + + String[] projection = new String[]{Video.VideoColumns.DURATION, + Video.VideoColumns.BOOKMARK}; + try { + Cursor cursor = getContentResolver().query(mUri, projection, null, null, null); + if (cursor != null) { + try { + if ( cursor.moveToFirst() ) { + int duration = getCursorInteger(cursor, 0); + int bookmark = getCursorInteger(cursor, 1); + final int ONE_MINUTE = 60 * 1000; + final int TWO_MINUTES = 2 * ONE_MINUTE; + final int FIVE_MINUTES = 5 * ONE_MINUTE; + if ((bookmark < TWO_MINUTES) + || (duration < FIVE_MINUTES) + || (bookmark > (duration - ONE_MINUTE))) { + return null; } - } finally { - cursor.close(); + + return new Integer(bookmark); } + } finally { + cursor.close(); } - } catch (SQLiteException e) { - // ignore } + } catch (SQLiteException e) { + // ignore } + return null; } @@ -173,19 +182,22 @@ public class MovieView extends Activity implements MediaPlayer.OnErrorListener, } private void setBookmark(int bookmark) { - String scheme = mUri.getScheme(); - if ("content".equalsIgnoreCase(scheme)) { - ContentValues values = new ContentValues(); - values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark)); - try { - getContentResolver().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. - } - } + if (!uriSupportsBookmarks(mUri)) { + return; + } + + ContentValues values = new ContentValues(); + values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark)); + try { + getContentResolver().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. + } } @Override diff --git a/src/com/android/camera/PhotoGadgetBind.java b/src/com/android/camera/PhotoGadgetBind.java new file mode 100644 index 0000000..fff19de --- /dev/null +++ b/src/com/android/camera/PhotoGadgetBind.java @@ -0,0 +1,73 @@ +/* + * 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.PhotoGadgetProvider.PhotoDatabaseHelper; + +import android.app.Activity; +import android.content.Intent; +import android.gadget.GadgetManager; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.util.Log; +import android.widget.RemoteViews; + +import java.util.ArrayList; + +public class PhotoGadgetBind extends Activity { + static final String TAG = "PhotoGadgetBind"; + + static final String EXTRA_GADGET_BITMAPS = "com.android.camera.gadgetbitmaps"; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + finish(); + + // The caller has requested that we bind a given bitmap to a specific + // gadgetId, which probably is happening during a Launcher upgrade. This + // is dangerous because the caller could set bitmaps on gadgetIds they + // don't own, so we guard this call at the manifest level by requiring + // the BIND_GADGET permission. + + final Intent intent = getIntent(); + final Bundle extras = intent.getExtras(); + + final int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS); + final ArrayList<Bitmap> bitmaps = extras.getParcelableArrayList(EXTRA_GADGET_BITMAPS); + + if (gadgetIds == null || bitmaps == null || + gadgetIds.length != bitmaps.size()) { + Log.e(TAG, "Problem parsing photo gadget bind request"); + return; + } + + GadgetManager gadgetManager = GadgetManager.getInstance(this); + PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); + for (int i = 0; i < gadgetIds.length; i++) { + // Store the cropped photo in our database + int gadgetId = gadgetIds[i]; + helper.setPhoto(gadgetId, bitmaps.get(i)); + + // Push newly updated gadget to surface + RemoteViews views = PhotoGadgetProvider.buildUpdate(this, gadgetId, helper); + gadgetManager.updateGadget(new int[] { gadgetId }, views); + } + helper.close(); + + } +} diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 05e33a6..0479e8b 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -67,7 +67,7 @@ import android.widget.TextView; import android.widget.Toast; public class VideoCamera extends Activity implements View.OnClickListener, - ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback { + ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback, MediaRecorder.OnErrorListener { private static final String TAG = "videocamera"; @@ -104,7 +104,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, private MediaRecorder mMediaRecorder; private boolean mMediaRecorderRecording = false; - private boolean mNeedToRegisterRecording; private long mRecordingStartTime; // The video file that the hardware camera is about to record into // (or is recording into.) @@ -195,16 +194,22 @@ public class VideoCamera extends Activity implements View.OnClickListener, @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { + if (action.equals(Intent.ACTION_MEDIA_EJECT)) { + mHasSdCard = false; + stopVideoRecording(); + initializeVideo(); + } else 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 updateStorageHint(); mHasSdCard = true; + initializeVideo(); } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) { // SD card unavailable updateStorageHint(); mHasSdCard = false; + releaseMediaRecorder(); } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) { Toast.makeText(VideoCamera.this, getResources().getString(R.string.wait), 5000); } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) { @@ -408,6 +413,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, // install an intent filter to receive SD card related events. IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); + intentFilter.addAction(Intent.ACTION_MEDIA_EJECT); intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED); intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); @@ -669,7 +675,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } mMediaRecorder = new MediaRecorder(); - mNeedToRegisterRecording = false; if (DEBUG_SUPPRESS_AUDIO_RECORDING) { Log.v(TAG, "DEBUG_SUPPRESS_AUDIO_RECORDING is true."); @@ -679,18 +684,21 @@ public class VideoCamera extends Activity implements View.OnClickListener, mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); - // We try Uri in intent first. If it doesn't work, use our own instead. - if (mCameraVideoFileDescriptor != null) { - mMediaRecorder.setOutputFile(mCameraVideoFileDescriptor); + if (!mHasSdCard) { + mMediaRecorder.setOutputFile("/dev/null"); } else { - createVideoPath(); - mMediaRecorder.setOutputFile(mCameraVideoFilename); + // We try Uri in intent first. If it doesn't work, use our own instead. + if (mCameraVideoFileDescriptor != null) { + mMediaRecorder.setOutputFile(mCameraVideoFileDescriptor); + } else { + createVideoPath(); + mMediaRecorder.setOutputFile(mCameraVideoFilename); + } } boolean videoQualityHigh = getBooleanPreference(CameraSettings.KEY_VIDEO_QUALITY, CameraSettings.DEFAULT_VIDEO_QUALITY_VALUE); - if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) { int extraVideoQuality = intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); videoQualityHigh = (extraVideoQuality > 0); @@ -849,6 +857,15 @@ public class VideoCamera extends Activity implements View.OnClickListener, item.setIcon(android.R.drawable.ic_menu_preferences); } + // from MediaRecorder.OnErrorListener + public void onError(MediaRecorder mr, int what, int extra) { + if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { + // We may have run out of space on the sdcard. + stopVideoRecording(); + updateStorageHint(); + } + } + private void startVideoRecording() { Log.v(TAG, "startVideoRecording"); if (!mMediaRecorderRecording) { @@ -859,10 +876,10 @@ public class VideoCamera extends Activity implements View.OnClickListener, } // Check mMediaRecorder to see whether it is initialized or not. - if (mMediaRecorder == null) { - initializeVideo(); - } + if (mMediaRecorder == null) initializeVideo(); + try { + mMediaRecorder.setOnErrorListener(this); mMediaRecorder.start(); // Recording is now started } catch (RuntimeException e) { Log.e(TAG, "Could not start media recorder. ", e); @@ -932,12 +949,18 @@ public class VideoCamera extends Activity implements View.OnClickListener, private void stopVideoRecording() { Log.v(TAG, "stopVideoRecording"); + boolean needToRegisterRecording = false; if (mMediaRecorderRecording || mMediaRecorder != null) { if (mMediaRecorderRecording && mMediaRecorder != null) { - mMediaRecorder.stop(); + try { + mMediaRecorder.setOnErrorListener(null); + mMediaRecorder.stop(); + } catch (RuntimeException e) { + Log.e(TAG, "stop fail: " + e.getMessage()); + } mCurrentVideoFilename = mCameraVideoFilename; Log.v(TAG, "Setting current video filename: " + mCurrentVideoFilename); - mNeedToRegisterRecording = true; + needToRegisterRecording = true; mMediaRecorderRecording = false; } releaseMediaRecorder(); @@ -945,10 +968,8 @@ public class VideoCamera extends Activity implements View.OnClickListener, mRecordingTimeView.setVisibility(View.GONE); setScreenTimeoutLong(); } - if (mNeedToRegisterRecording) { - registerVideo(); - mNeedToRegisterRecording = false; - } + if (needToRegisterRecording && mHasSdCard) registerVideo(); + mCameraVideoFilename = null; mCameraVideoFileDescriptor = null; } diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java index ad27ae3..07d396f 100644 --- a/src/com/android/camera/ViewImage.java +++ b/src/com/android/camera/ViewImage.java @@ -34,7 +34,7 @@ import android.provider.MediaStore; import android.util.AttributeSet; import android.util.Config; import android.util.Log; -import android.view.GestureDetector; +import android.view.GestureDetector; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -48,6 +48,7 @@ import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.Scroller; import android.widget.Toast; +import android.widget.ZoomButtonsController; import android.widget.ZoomRingController; import com.android.camera.ImageManager.IImage; @@ -127,6 +128,9 @@ public class ViewImage extends Activity implements View.OnClickListener private Runnable mDismissOnScreenControlsRunnable; private boolean mCameraReviewMode; + private int mCurrentOrientation; + + public ViewImage() { } @@ -226,38 +230,41 @@ public class ViewImage extends Activity implements View.OnClickListener private ViewImage mViewImage; private boolean mEnableTrackballScroll; private GestureDetector mGestureDetector; - - private static int TOUCH_AREA_WIDTH = 60; - // Returns current scale step (numbered from 0 to 10). + private static int TOUCH_AREA_WIDTH = 60; + + // The zoom ring setup: + // We limit the thumb on the zoom ring in the range 0 to 5/3*PI. The + // last PI/3 of the ring is left as a region that the thumb can't go in. + // The 5/3*PI range is divided into 60 steps. Each step scales the image + // by mScaleRate. We make mScaleRate^60 = maxZoom(). + + // This is the max step value we can have for the zoom ring. + private static int MAX_STEP = 60; + // This is the angle we used to separate each step. + private static float STEP_ANGLE = (5 * (float) Math.PI / 3) / MAX_STEP; + // The scale rate for each step. + private float mScaleRate; + + // Returns current scale step (numbered from 0 to MAX_STEP). private int getCurrentStep() { float s = getScale(); - float b = sScaleRate; + float b = mScaleRate; int step = (int)Math.round(Math.log(s) / Math.log(b)); - return Math.max(0, Math.min(10, step)); + return Math.max(0, Math.min(MAX_STEP, step)); } - // Returns the max scale step this image can use. - private int getMaxStep() { - float s = maxZoom(); - float b = sScaleRate; - int step = (int)Math.ceil(Math.log(s) / Math.log(b)); - return Math.max(0, Math.min(10, step)); - } - - // The setup we use here is to have 12 steps (only 0 to 10 are used), - // each separated by angle PI/6. We allow clockwise rotation (zoom-in) - // from the beginning position only. So we set counter clockwise bound - // to 0 and set clockwise bound to (2 - N/6) * PI. (clockwise angle - // is negative, and we need to mod 2*PI for the API to work.) + // Limit the thumb on the zoom ring in the range 0 to 5/3*PI. (clockwise + // angle is negative, and we need to mod 2*PI for the API to work.) private void setZoomRingBounds() { - int max_step = getMaxStep(); - float max_angle = (2 - max_step / 6F) * (float)Math.PI; - mZoomRingController.setResetThumbAutomatically(false); - mZoomRingController.setThumbClockwiseBound(max_angle); + mScaleRate = (float) Math.pow(maxZoom(), 1.0 / MAX_STEP); + float limit = (2 - 5 / 3F) * (float) Math.PI; + mZoomRingController.setThumbClockwiseBound(limit); mZoomRingController.setThumbCounterclockwiseBound(0); } + private ZoomButtonsController mZoomButtonsController; + // The zoom ring is set to visible by a double tap. private ZoomRingController mZoomRingController; private ZoomRingController.OnZoomListener mZoomListener = @@ -276,17 +283,17 @@ public class ViewImage extends Activity implements View.OnClickListener public void onEndPan() { } - + // The clockwise angle is negative, so we need to mod 2*PI private float stepToAngle(int step) { - float angle = step * (float)Math.PI / 6; - angle = (float)Math.PI * 2 - angle; + float angle = step * STEP_ANGLE; + angle = (float) Math.PI * 2 - angle; return angle; } - + private int angleToStep(double angle) { angle = Math.PI * 2 - angle; - int step = (int)Math.round(angle / (Math.PI / 6)); + int step = (int)Math.round(angle / STEP_ANGLE); return step; } @@ -320,14 +327,11 @@ public class ViewImage extends Activity implements View.OnClickListener int deltaY = getHeight() / 2 - centerY; panBy(deltaX, deltaY); - // Do zoom in/out. - while (deltaStep > 0) { - zoomIn(); - deltaStep--; - } - while (deltaStep < 0) { - zoomOut(); - deltaStep++; + // Do zoom in/out. + if (deltaStep > 0) { + zoomIn((float) Math.pow(mScaleRate, deltaStep)); + } else if (deltaStep < 0) { + zoomOut((float) Math.pow(mScaleRate, -deltaStep)); } // Reverse the first centering. @@ -356,9 +360,31 @@ public class ViewImage extends Activity implements View.OnClickListener private void setup(Context context) { mViewImage = (ViewImage) context; mZoomRingController = new ZoomRingController(context, this); + mZoomRingController.setVibration(false); + mZoomRingController.setZoomCallbackThreshold(STEP_ANGLE); + mZoomRingController.setResetThumbAutomatically(false); mZoomRingController.setCallback(mZoomListener); - mGestureDetector = new GestureDetector(new MyGestureListener()); + mGestureDetector = new GestureDetector(getContext(), new MyGestureListener()); mGestureDetector.setOnDoubleTapListener(new MyDoubleTapListener()); + mZoomButtonsController = new ZoomButtonsController(context, this); + mZoomButtonsController.setOverviewVisible(false); + mZoomButtonsController.setCallback(new ZoomButtonsController.OnZoomListener() { + + public void onCenter(int x, int y) { + mZoomListener.onCenter(x, y); + } + + public void onOverview() { + } + + public void onVisibilityChanged(boolean visible) { + mZoomListener.onVisibilityChanged(visible); + } + + public void onZoom(boolean zoomIn) { + mZoomListener.onSimpleZoom(zoomIn); + } + }); } public void setEnableTrackballScroll(boolean enable) { @@ -393,34 +419,40 @@ public class ViewImage extends Activity implements View.OnClickListener return true; } } - + private class MyDoubleTapListener implements GestureDetector.OnDoubleTapListener { // On single tap, we show the arrows. We also change to the - // prev/next image if the user taps on the left/right region. + // prev/next image if the user taps on the left/right region. public boolean onSingleTapConfirmed(MotionEvent e) { ViewImage viewImage = mViewImage; int viewWidth = getWidth(); int x = (int) e.getX(); - int y = (int) e.getY(); + int y = (int) e.getY(); if (x < TOUCH_AREA_WIDTH) { viewImage.moveNextOrPrevious(-1); } else if (x > viewWidth - TOUCH_AREA_WIDTH) { viewImage.moveNextOrPrevious(1); } - + viewImage.setMode(MODE_NORMAL); viewImage.showOnScreenControls(); return true; } - + // On double tap, we show the zoom ring control. public boolean onDoubleTapEvent(MotionEvent e) { mViewImage.setMode(MODE_NORMAL); - mZoomRingController.setVisible(true); + mZoomRingController.handleDoubleTapEvent(e); + mZoomButtonsController.handleDoubleTapEvent(e); return true; } + + public boolean onDoubleTap(MotionEvent e) { + return false; + } + } @Override @@ -524,6 +556,7 @@ public class ViewImage extends Activity implements View.OnClickListener @Override protected void onDetachedFromWindow() { mZoomRingController.setVisible(false); + mZoomButtonsController.setVisible(false); } } @@ -704,28 +737,27 @@ public class ViewImage extends Activity implements View.OnClickListener mImageMenuRunnable.gettingReadyToOpen(menu, mAllImages.getImageAt(mCurrentPosition)); } - menu.findItem(MenuHelper.MENU_IMAGE_SHARE).setEnabled(isCurrentImageShareable()); - - return true; - } - - private boolean isCurrentImageShareable() { - IImage image = mAllImages.getImageAt(mCurrentPosition); - if (image != null){ - Uri uri = image.fullSizeImageUri(); - String fullUri = uri.toString(); - return fullUri.startsWith(MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString()) || - fullUri.startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString()); - } return true; } @Override public void onConfigurationChanged(android.content.res.Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (newConfig.orientation != getResources().getConfiguration().orientation) { + boolean changed = mCurrentOrientation != newConfig.orientation; + mCurrentOrientation = newConfig.orientation; + if (changed) { + if (mGetter != null) { + // kill off any background image fetching + mGetter.cancelCurrent(); + mGetter.stop(); + } + makeGetter(); + mFirst = true; + + // clear off the current set of images since we need to reload + // them at the right size for (ImageViewTouchBase iv: mImageViews) { - iv.setImageBitmapResetBase(null, false, true); + iv.clear(); } MenuHelper.requestOrientation(this, mPrefs); } @@ -1090,6 +1122,7 @@ public class ViewImage extends Activity implements View.OnClickListener mShowActionIcons = intent.getBooleanExtra(MediaStore.EXTRA_SHOW_ACTION_ICONS, false); mPrefs = PreferenceManager.getDefaultSharedPreferences(this); + mCurrentOrientation = getResources().getConfiguration().orientation; setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT); requestWindowFeature(Window.FEATURE_NO_TITLE); @@ -1196,9 +1229,6 @@ public class ViewImage extends Activity implements View.OnClickListener } setOrientation(); - - // Show a tutorial for the new zoom interaction (the method ensure we only show it once) - ZoomRingController.showZoomTutorialOnce(this); } private void setOrientation() { @@ -1527,6 +1557,9 @@ public class ViewImage extends Activity implements View.OnClickListener setImage(mCurrentPosition); setOrientation(); + + // Show a tutorial for the new zoom interaction (the method ensure we only show it once) + ZoomRingController.showZoomTutorialOnce(this); } @Override @@ -1550,6 +1583,7 @@ public class ViewImage extends Activity implements View.OnClickListener iv.recycleBitmaps(); iv.setImageBitmap(null, true); } + ZoomRingController.finishZoomTutorial(this, false); } @Override |