diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-19 23:08:56 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-19 23:08:56 -0700 |
commit | e7b339c91b554539119abecaf53f552982f60477 (patch) | |
tree | 5d2007c8fc17b2be9da98680b9ee16ae149922eb | |
parent | de365d87520c97d6b1636442e6b5c82a3e036f29 (diff) | |
download | LegacyCamera-e7b339c91b554539119abecaf53f552982f60477.zip LegacyCamera-e7b339c91b554539119abecaf53f552982f60477.tar.gz LegacyCamera-e7b339c91b554539119abecaf53f552982f60477.tar.bz2 |
auto import from //branches/cupcake_rel/...@141571
40 files changed, 571 insertions, 519 deletions
diff --git a/res/drawable/frame_thumbnail_default.png b/res/drawable/frame_thumbnail_default.png Binary files differindex a7498db..a531790 100644 --- a/res/drawable/frame_thumbnail_default.png +++ b/res/drawable/frame_thumbnail_default.png diff --git a/res/drawable/frame_thumbnail_pressed.png b/res/drawable/frame_thumbnail_pressed.png Binary files differindex ebc6855..3be8138 100644 --- a/res/drawable/frame_thumbnail_pressed.png +++ b/res/drawable/frame_thumbnail_pressed.png diff --git a/res/drawable/frame_thumbnail_selected.png b/res/drawable/frame_thumbnail_selected.png Binary files differindex 429a318..5884f9c 100644 --- a/res/drawable/frame_thumbnail_selected.png +++ b/res/drawable/frame_thumbnail_selected.png diff --git a/res/drawable/ic_btn_actionmenu_attach_default.png b/res/drawable/ic_btn_actionmenu_attach_default.png Binary files differindex 043691d..c8f7ec7 100644 --- a/res/drawable/ic_btn_actionmenu_attach_default.png +++ b/res/drawable/ic_btn_actionmenu_attach_default.png diff --git a/res/drawable/ic_btn_actionmenu_attach_pressed.png b/res/drawable/ic_btn_actionmenu_attach_pressed.png Binary files differindex b092ac1..7753e5b 100644 --- a/res/drawable/ic_btn_actionmenu_attach_pressed.png +++ b/res/drawable/ic_btn_actionmenu_attach_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_attach_selected.png b/res/drawable/ic_btn_actionmenu_attach_selected.png Binary files differindex 52a2ef0..ca7e775 100644 --- a/res/drawable/ic_btn_actionmenu_attach_selected.png +++ b/res/drawable/ic_btn_actionmenu_attach_selected.png diff --git a/res/drawable/ic_btn_actionmenu_cancel_default.png b/res/drawable/ic_btn_actionmenu_cancel_default.png Binary files differindex cb8f7bc..ac7169a 100644 --- a/res/drawable/ic_btn_actionmenu_cancel_default.png +++ b/res/drawable/ic_btn_actionmenu_cancel_default.png diff --git a/res/drawable/ic_btn_actionmenu_cancel_pressed.png b/res/drawable/ic_btn_actionmenu_cancel_pressed.png Binary files differindex 02bdb49..ecb1a1f 100644 --- a/res/drawable/ic_btn_actionmenu_cancel_pressed.png +++ b/res/drawable/ic_btn_actionmenu_cancel_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_cancel_selected.png b/res/drawable/ic_btn_actionmenu_cancel_selected.png Binary files differindex a0b6017..235ee88 100644 --- a/res/drawable/ic_btn_actionmenu_cancel_selected.png +++ b/res/drawable/ic_btn_actionmenu_cancel_selected.png diff --git a/res/drawable/ic_btn_actionmenu_delete_default.png b/res/drawable/ic_btn_actionmenu_delete_default.png Binary files differindex 7e25f0d..f3f655e 100644 --- a/res/drawable/ic_btn_actionmenu_delete_default.png +++ b/res/drawable/ic_btn_actionmenu_delete_default.png diff --git a/res/drawable/ic_btn_actionmenu_delete_pressed.png b/res/drawable/ic_btn_actionmenu_delete_pressed.png Binary files differindex 94087f6..14a21a8 100644 --- a/res/drawable/ic_btn_actionmenu_delete_pressed.png +++ b/res/drawable/ic_btn_actionmenu_delete_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_delete_selected.png b/res/drawable/ic_btn_actionmenu_delete_selected.png Binary files differindex 780310b..2ddb0a6 100644 --- a/res/drawable/ic_btn_actionmenu_delete_selected.png +++ b/res/drawable/ic_btn_actionmenu_delete_selected.png diff --git a/res/drawable/ic_btn_actionmenu_gallery_default.png b/res/drawable/ic_btn_actionmenu_gallery_default.png Binary files differindex a2d38db..4d3456c 100644 --- a/res/drawable/ic_btn_actionmenu_gallery_default.png +++ b/res/drawable/ic_btn_actionmenu_gallery_default.png diff --git a/res/drawable/ic_btn_actionmenu_gallery_pressed.png b/res/drawable/ic_btn_actionmenu_gallery_pressed.png Binary files differindex a01b7f8..4c29587 100644 --- a/res/drawable/ic_btn_actionmenu_gallery_pressed.png +++ b/res/drawable/ic_btn_actionmenu_gallery_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_gallery_selected.png b/res/drawable/ic_btn_actionmenu_gallery_selected.png Binary files differindex 400a63b..27349d4 100644 --- a/res/drawable/ic_btn_actionmenu_gallery_selected.png +++ b/res/drawable/ic_btn_actionmenu_gallery_selected.png diff --git a/res/drawable/ic_btn_actionmenu_play_default.png b/res/drawable/ic_btn_actionmenu_play_default.png Binary files differindex 17e0748..eba780b 100644 --- a/res/drawable/ic_btn_actionmenu_play_default.png +++ b/res/drawable/ic_btn_actionmenu_play_default.png diff --git a/res/drawable/ic_btn_actionmenu_play_pressed.png b/res/drawable/ic_btn_actionmenu_play_pressed.png Binary files differindex c671669..1caa2c2 100644 --- a/res/drawable/ic_btn_actionmenu_play_pressed.png +++ b/res/drawable/ic_btn_actionmenu_play_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_play_selected.png b/res/drawable/ic_btn_actionmenu_play_selected.png Binary files differindex 35e1425..fea0ba0 100644 --- a/res/drawable/ic_btn_actionmenu_play_selected.png +++ b/res/drawable/ic_btn_actionmenu_play_selected.png diff --git a/res/drawable/ic_btn_actionmenu_set_as_default.png b/res/drawable/ic_btn_actionmenu_set_as_default.png Binary files differindex 0d341c7..048024f 100644 --- a/res/drawable/ic_btn_actionmenu_set_as_default.png +++ b/res/drawable/ic_btn_actionmenu_set_as_default.png diff --git a/res/drawable/ic_btn_actionmenu_set_as_pressed.png b/res/drawable/ic_btn_actionmenu_set_as_pressed.png Binary files differindex 58dc85c..67ae2aa 100644 --- a/res/drawable/ic_btn_actionmenu_set_as_pressed.png +++ b/res/drawable/ic_btn_actionmenu_set_as_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_set_as_selected.png b/res/drawable/ic_btn_actionmenu_set_as_selected.png Binary files differindex 6281229..f2e5fce 100644 --- a/res/drawable/ic_btn_actionmenu_set_as_selected.png +++ b/res/drawable/ic_btn_actionmenu_set_as_selected.png diff --git a/res/drawable/ic_btn_actionmenu_share_default.png b/res/drawable/ic_btn_actionmenu_share_default.png Binary files differindex 19f6ef4..8e66365 100644 --- a/res/drawable/ic_btn_actionmenu_share_default.png +++ b/res/drawable/ic_btn_actionmenu_share_default.png diff --git a/res/drawable/ic_btn_actionmenu_share_grayout.png b/res/drawable/ic_btn_actionmenu_share_grayout.png Binary files differindex f41db23..4b62023 100755 --- a/res/drawable/ic_btn_actionmenu_share_grayout.png +++ b/res/drawable/ic_btn_actionmenu_share_grayout.png diff --git a/res/drawable/ic_btn_actionmenu_share_pressed.png b/res/drawable/ic_btn_actionmenu_share_pressed.png Binary files differindex 8583114..be71235 100644 --- a/res/drawable/ic_btn_actionmenu_share_pressed.png +++ b/res/drawable/ic_btn_actionmenu_share_pressed.png diff --git a/res/drawable/ic_btn_actionmenu_share_selected.png b/res/drawable/ic_btn_actionmenu_share_selected.png Binary files differindex fc9679b..fd4f886 100644 --- a/res/drawable/ic_btn_actionmenu_share_selected.png +++ b/res/drawable/ic_btn_actionmenu_share_selected.png diff --git a/res/drawable/ic_btn_camera_default_background.png b/res/drawable/ic_btn_camera_default_background.png Binary files differindex 5dac9c1..d58e2d2 100644 --- a/res/drawable/ic_btn_camera_default_background.png +++ b/res/drawable/ic_btn_camera_default_background.png diff --git a/res/drawable/ic_btn_camera_pressed_background.png b/res/drawable/ic_btn_camera_pressed_background.png Binary files differindex ebc6855..e0f7e12 100644 --- a/res/drawable/ic_btn_camera_pressed_background.png +++ b/res/drawable/ic_btn_camera_pressed_background.png diff --git a/res/drawable/ic_btn_camera_selected_background.png b/res/drawable/ic_btn_camera_selected_background.png Binary files differindex 429a318..3d7549b 100644 --- a/res/drawable/ic_btn_camera_selected_background.png +++ b/res/drawable/ic_btn_camera_selected_background.png diff --git a/res/drawable/ic_camera_indicator_photo.png b/res/drawable/ic_camera_indicator_photo.png Binary files differindex 3b0483b..d6c02da 100644 --- a/res/drawable/ic_camera_indicator_photo.png +++ b/res/drawable/ic_camera_indicator_photo.png diff --git a/res/drawable/ic_camera_indicator_video.png b/res/drawable/ic_camera_indicator_video.png Binary files differindex a4cb8d0..c160c66 100644 --- a/res/drawable/ic_camera_indicator_video.png +++ b/res/drawable/ic_camera_indicator_video.png diff --git a/res/drawable/ic_gps_active_camera.png b/res/drawable/ic_gps_active_camera.png Binary files differnew file mode 100755 index 0000000..9814772 --- /dev/null +++ b/res/drawable/ic_gps_active_camera.png diff --git a/res/drawable/ic_launcher_camera.png b/res/drawable/ic_launcher_camera.png Binary files differindex 9bb4c61..c2d7606 100644 --- a/res/drawable/ic_launcher_camera.png +++ b/res/drawable/ic_launcher_camera.png diff --git a/res/layout/camera.xml b/res/layout/camera.xml index 02d8430..767beaa 100644 --- a/res/layout/camera.xml +++ b/res/layout/camera.xml @@ -4,9 +4,9 @@ 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. @@ -25,7 +25,7 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" /> - + <com.android.camera.ShutterButton android:id="@+id/shutter_button" android:layout_width="wrap_content" @@ -36,11 +36,24 @@ android:focusable="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" - android:layout_marginRight="10dip" - android:layout_marginTop="10dip" + android:layout_marginRight="5dip" + android:layout_marginTop="5dip" android:scaleType="center" /> <ImageView + android:id="@+id/gps_indicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="invisible" + android:clickable="false" + android:focusable="false" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:layout_marginRight="18dip" + android:layout_marginTop="18dip" + android:src="@drawable/ic_gps_active_camera" /> + + <ImageView android:id="@+id/focus_indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -51,7 +64,7 @@ android:layout_marginTop="16dip" android:scaleType="center" android:visibility="gone" /> - + <ImageView android:visibility="gone" android:id="@+id/last_picture_button" @@ -61,6 +74,6 @@ android:focusable="false" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" - android:layout_marginLeft="10dip" - android:layout_marginTop="10dip" /> + android:layout_marginLeft="5dip" + android:layout_marginTop="5dip" /> </RelativeLayout> diff --git a/res/layout/video_camera.xml b/res/layout/video_camera.xml index bafcd09..b8981cc 100644 --- a/res/layout/video_camera.xml +++ b/res/layout/video_camera.xml @@ -4,9 +4,9 @@ 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. @@ -24,114 +24,107 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" - /> - - <ImageView - android:id="@+id/video_frame" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:visibility="gone" /> - + <ImageView - android:id="@+id/blackout" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:visibility="invisible" + android:id="@+id/video_frame" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:visibility="gone" /> <com.android.camera.ShutterButton - android:id="@+id/shutter_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_camera_indicator_video" - android:background="@drawable/ic_btn_camera_background" - android:clickable="true" - android:focusable="true" - android:layout_alignParentRight="true" - android:layout_alignParentTop="true" - android:layout_marginRight="10dip" - android:layout_marginTop="10dip" - android:scaleType="center"/> + android:id="@+id/shutter_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_camera_indicator_video" + android:background="@drawable/ic_btn_camera_background" + android:clickable="true" + android:focusable="true" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:layout_marginRight="5dip" + android:layout_marginTop="5dip" + android:scaleType="center" /> <!-- Note: In this TextView the paddingRight="2" attribute is required because otherwise the text's drop shadow will be clipped. --> <TextView - android:id="@+id/recording_time" - android:layout_width="90dip" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/shutter_button" - android:layout_alignTop="@id/shutter_button" - android:layout_marginTop="20dip" - android:layout_marginRight="6dip" - android:paddingRight="2dip" - android:shadowColor="#c0000000" - android:shadowDx="1" - android:shadowDy="1" - android:shadowRadius="1" - android:gravity="right" - android:textColor="@color/recording_time_elapsed_text" - android:textSize="20dip" - android:textStyle="bold" - android:visibility="gone"/> + android:id="@+id/recording_time" + android:layout_width="90dip" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/shutter_button" + android:layout_alignTop="@id/shutter_button" + android:layout_marginTop="20dip" + android:layout_marginRight="6dip" + android:paddingRight="2dip" + android:shadowColor="#c0000000" + android:shadowDx="1" + android:shadowDy="1" + android:shadowRadius="1" + android:gravity="right" + android:textColor="@color/recording_time_elapsed_text" + android:textSize="20dip" + android:textStyle="bold" + android:visibility="gone"/> - <LinearLayout - android:visibility="gone" - android:id="@+id/post_picture_panel" - android:layout_alignTop="@id/shutter_button" - android:layout_toLeftOf="@id/shutter_button" + <LinearLayout + android:visibility="gone" + android:id="@+id/post_picture_panel" + android:layout_alignTop="@id/shutter_button" + android:layout_toLeftOf="@id/shutter_button" android:layout_marginRight="38dip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal"> <com.android.camera.ActionMenuButton - android:id="@+id/gallery" - android:drawableTop="@drawable/ic_menu_gallery" - android:text="@string/camera_gallery" - style="@style/OnscreenActionIcon" + android:id="@+id/gallery" + android:drawableTop="@drawable/ic_menu_gallery" + android:text="@string/camera_gallery" + style="@style/OnscreenActionIcon" + /> + <com.android.camera.ActionMenuButton + android:id="@+id/play" + android:drawableTop="@drawable/ic_menu_camera_play" + android:text="@string/camera_play" + style="@style/OnscreenActionIcon" /> <com.android.camera.ActionMenuButton - android:id="@+id/play" - android:drawableTop="@drawable/ic_menu_camera_play" - android:text="@string/camera_play" - style="@style/OnscreenActionIcon" - /> - <com.android.camera.ActionMenuButton - android:id="@+id/share" - android:drawableTop="@drawable/ic_menu_share" - android:text="@string/camera_share" - style="@style/OnscreenActionIcon" - /> - <com.android.camera.ActionMenuButton - android:id="@+id/discard" - android:drawableTop="@drawable/ic_menu_delete" - android:text="@string/camera_toss" - style="@style/OnscreenActionIcon" - /> - <com.android.camera.ActionMenuButton - android:id="@+id/attach" - android:drawableTop="@drawable/ic_menu_attach" - android:text="@string/camera_attach" - style="@style/OnscreenActionIcon" - /> - <com.android.camera.ActionMenuButton - android:id="@+id/cancel" - android:drawableTop="@drawable/ic_menu_cancel" - android:text="@string/camera_cancel" - style="@style/OnscreenActionIcon" - /> - </LinearLayout> + android:id="@+id/share" + android:drawableTop="@drawable/ic_menu_share" + android:text="@string/camera_share" + style="@style/OnscreenActionIcon" + /> + <com.android.camera.ActionMenuButton + android:id="@+id/discard" + android:drawableTop="@drawable/ic_menu_delete" + android:text="@string/camera_toss" + style="@style/OnscreenActionIcon" + /> + <com.android.camera.ActionMenuButton + android:id="@+id/attach" + android:drawableTop="@drawable/ic_menu_attach" + android:text="@string/camera_attach" + style="@style/OnscreenActionIcon" + /> + <com.android.camera.ActionMenuButton + android:id="@+id/cancel" + android:drawableTop="@drawable/ic_menu_cancel" + android:text="@string/camera_cancel" + style="@style/OnscreenActionIcon" + /> + </LinearLayout> <ImageView - android:visibility="visible" - android:id="@+id/last_picture_button" - android:layout_width="72dip" - android:layout_height="72dip" - android:clickable="true" - android:focusable="false" - android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" - android:layout_marginLeft="10dip" - android:layout_marginTop="10dip" /> + android:visibility="visible" + android:id="@+id/last_picture_button" + android:layout_width="72dip" + android:layout_height="72dip" + android:clickable="true" + android:focusable="false" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_marginLeft="5dip" + android:layout_marginTop="5dip"/> </RelativeLayout> diff --git a/res/raw/camera_click.ogg b/res/raw/camera_click.ogg Binary files differdeleted file mode 100644 index 0a769ff..0000000 --- a/res/raw/camera_click.ogg +++ /dev/null diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 8cd1756..2300387 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -16,12 +16,7 @@ package com.android.camera; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -29,7 +24,6 @@ import java.io.OutputStream; import java.util.ArrayList; import android.app.Activity; -import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -37,27 +31,16 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Canvas; import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.TransitionDrawable; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; import android.media.AudioManager; -import android.media.MediaPlayer; import android.media.ToneGenerator; import android.net.Uri; import android.os.Bundle; @@ -79,7 +62,6 @@ import android.view.OrientationEventListener; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.animation.AlphaAnimation; @@ -139,8 +121,6 @@ public class Camera extends Activity implements View.OnClickListener, private int mViewFinderWidth, mViewFinderHeight; private boolean mPreviewing = false; - private MediaPlayer mClickSound; - private Capturer mCaptureObject; private ImageCapture mImageCapture = null; @@ -158,21 +138,13 @@ public class Camera extends Activity implements View.OnClickListener, private ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>(); - private ImageView mLastPictureButton; - private LayerDrawable mVignette; - private Animation mShowLastPictureButtonAnimation = new AlphaAnimation(0F, 1F); - private boolean mShouldShowLastPictureButton; - private TransitionDrawable mThumbnailTransition; - private Drawable[] mThumbnails; - private boolean mShouldTransitionThumbnails; - private Uri mLastPictureUri; - private Bitmap mLastPictureThumb; private LocationManager mLocationManager = null; private ShutterButton mShutterButton; private Animation mFocusBlinkAnimation; private View mFocusIndicator; + private ImageView mGpsIndicator; private ToneGenerator mFocusToneGenerator; @@ -185,12 +157,16 @@ public class Camera extends Activity implements View.OnClickListener, private long mShutterCallbackTime; private long mRawPictureCallbackTime; private int mPicturesRemaining; + private boolean mRecordLocation; private boolean mKeepAndRestartPreview; - // mPostCaptureAlert is non-null only if isImageCaptureIntent() is true. + private boolean mIsImageCaptureIntent; + // mPostCaptureAlert, mLastPictureButton, mThumbController + // are non-null only if isImageCaptureIntent() is true. private View mPostCaptureAlert; - + private ImageView mLastPictureButton; + private ThumbnailController mThumbController; private Handler mHandler = new MainHandler(); @@ -267,6 +243,12 @@ public class Camera extends Activity implements View.OnClickListener, // Hack to filter out 0.0,0.0 locations return; } + // If GPS is available before start camera, we won't get status + // update so update GPS indicator when we receive data. + if (mRecordLocation + && LocationManager.GPS_PROVIDER.equals(mProvider)) { + mGpsIndicator.setVisibility(View.VISIBLE); + } mLastLocation.set(newLocation); mValid = true; } @@ -279,8 +261,16 @@ public class Camera extends Activity implements View.OnClickListener, } public void onStatusChanged(String provider, int status, Bundle extras) { - if (status == LocationProvider.OUT_OF_SERVICE) { - mValid = false; + switch(status) { + case LocationProvider.OUT_OF_SERVICE: + case LocationProvider.TEMPORARILY_UNAVAILABLE: { + mValid = false; + if (mRecordLocation && + LocationManager.GPS_PROVIDER.equals(provider)) { + mGpsIndicator.setVisibility(View.INVISIBLE); + } + break; + } } } @@ -307,10 +297,6 @@ public class Camera extends Activity implements View.OnClickListener, // and so that we can see the full image that was taken. Size pictureSize = mParameters.getPictureSize(); mSurfaceView.setAspectRatio(pictureSize.width, pictureSize.height); - - if (mClickSound != null) { - mClickSound.start(); - } } }; @@ -480,7 +466,7 @@ public class Camera extends Activity implements View.OnClickListener, } public void storeImage(byte[] data, android.hardware.Camera camera, Location loc) { - boolean captureOnly = isImageCaptureIntent(); + boolean captureOnly = mIsImageCaptureIntent; if (!captureOnly) { storeImage(data, loc); @@ -543,8 +529,7 @@ public class Camera extends Activity implements View.OnClickListener, final int latchedOrientation = ImageManager.roundOrientation(mLastOrientation + 90); - Boolean recordLocation = mPreferences.getBoolean("pref_camera_recordlocation_key", false); - Location loc = recordLocation ? getCurrentLocation() : null; + Location loc = mRecordLocation ? getCurrentLocation() : null; // Quality 75 has visible artifacts, and quality 90 looks great but the files begin to // get large. 85 is a good compromise between the two. mParameters.set("jpeg-quality", 85); @@ -587,10 +572,6 @@ public class Camera extends Activity implements View.OnClickListener, mCameraDevice.setParameters(mParameters); mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback, new JpegPictureCallback(loc)); - // Prepare the sound to play in shutter callback. - if (mClickSound != null) { - mClickSound.seekTo(0); - } } public void onSnap() { @@ -618,7 +599,7 @@ public class Camera extends Activity implements View.OnClickListener, mKeepAndRestartPreview = true; - boolean getContentAction = isImageCaptureIntent(); + boolean getContentAction = mIsImageCaptureIntent; if (getContentAction) { mImageCapture.initiate(true); } else { @@ -637,63 +618,8 @@ public class Camera extends Activity implements View.OnClickListener, private void setLastPictureThumb(byte[] data, Uri uri) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 16; - Bitmap lastPictureThumb = BitmapFactory.decodeByteArray(data, 0, data.length, options); - - setLastPictureThumb(lastPictureThumb, uri); - } - - private static Bitmap makeRoundedCorner(Bitmap thumb, int rx, int ry) { - if (thumb == null) return null; - int width = thumb.getWidth(); - int height = thumb.getHeight(); - - Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(result); - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setStyle(Paint.Style.FILL); - canvas.drawRoundRect(new RectF(0, 0, width, height), rx, ry, paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(thumb, 0, 0, paint); - return result; - } - - private void setLastPictureThumb(Bitmap lastPictureThumb, Uri uri) { - - final int PADDING_WIDTH = 6; - final int PADDING_HEIGHT = 6; - LayoutParams layoutParams = mLastPictureButton.getLayoutParams(); - // Make the mini-thumbnail size smaller than the button size so that the image corners - // don't peek out from the rounded corners of the frame_thumbnail graphic: - final int miniThumbWidth = layoutParams.width - 2 * PADDING_WIDTH; - final int miniThumbHeight = layoutParams.height - 2 * PADDING_HEIGHT; - mLastPictureThumb = ImageManager.extractMiniThumb( - lastPictureThumb, miniThumbWidth, miniThumbHeight); - lastPictureThumb = makeRoundedCorner(mLastPictureThumb, 3, 3); - - Drawable[] vignetteLayers = new Drawable[2]; - vignetteLayers[0] = getResources().getDrawable(R.drawable.frame_thumbnail); - if (mThumbnails == null) { - mThumbnails = new Drawable[2]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - vignetteLayers[1] = mThumbnails[1]; - } else { - mThumbnails[0] = mThumbnails[1]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - mThumbnailTransition = new TransitionDrawable(mThumbnails); - mShouldTransitionThumbnails = true; - vignetteLayers[1] = mThumbnailTransition; - } - - mVignette = new LayerDrawable(vignetteLayers); - mVignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, - PADDING_WIDTH, PADDING_HEIGHT); - mLastPictureButton.setImageDrawable(mVignette); - - if (mLastPictureButton.getVisibility() != View.VISIBLE) { - mShouldShowLastPictureButton = true; - } - mLastPictureUri = uri; + mThumbController.setData(uri, lastPictureThumb); } static private String createName(long dateTaken) { @@ -761,6 +687,7 @@ public class Camera extends Activity implements View.OnClickListener, setContentView(R.layout.camera); mSurfaceView = (VideoPreview) findViewById(R.id.camera_preview); + mGpsIndicator = (ImageView) findViewById(R.id.gps_indicator); // don't set mSurfaceHolder here. We have it set ONLY within // surfaceCreated / surfaceDestroyed, other parts of the code @@ -769,38 +696,27 @@ public class Camera extends Activity implements View.OnClickListener, holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - if (!isImageCaptureIntent()) { + mIsImageCaptureIntent = isImageCaptureIntent(); + + if (!mIsImageCaptureIntent) { mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); mLastPictureButton.setOnClickListener(this); - loadLastThumb(); + Drawable frame = getResources().getDrawable(R.drawable.frame_thumbnail); + mThumbController = new ThumbnailController(mLastPictureButton, + frame, mContentResolver); + mThumbController.loadData(ImageManager.getLastImageThumbPath()); } mShutterButton = (ShutterButton) findViewById(R.id.shutter_button); mShutterButton.setOnShutterButtonListener(this); - try { - mClickSound = new MediaPlayer(); - AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.camera_click); - - mClickSound.setDataSource(afd.getFileDescriptor(), - afd.getStartOffset(), - afd.getLength()); - - if (mClickSound != null) { - mClickSound.setAudioStreamType(AudioManager.STREAM_ALARM); - mClickSound.prepare(); - } - } catch (Exception ex) { - Log.w(TAG, "Couldn't create click sound", ex); - } - mFocusIndicator = findViewById(R.id.focus_indicator); mFocusBlinkAnimation = AnimationUtils.loadAnimation(this, R.anim.auto_focus_blink); mFocusBlinkAnimation.setRepeatCount(Animation.INFINITE); mFocusBlinkAnimation.setRepeatMode(Animation.REVERSE); // We load the post_picture_panel layout only if it is needed. - if (isImageCaptureIntent()) { + if (mIsImageCaptureIntent) { ViewGroup cameraView = (ViewGroup)findViewById(R.id.camera); getLayoutInflater().inflate(R.layout.post_picture_panel, cameraView); @@ -1021,6 +937,9 @@ public class Camera extends Activity implements View.OnClickListener, mPausing = false; mOrientationListener.enable(); + mRecordLocation = mPreferences.getBoolean( + "pref_camera_recordlocation_key", false); + mGpsIndicator.setVisibility(View.INVISIBLE); // install an intent filter to receive SD card related events. IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); @@ -1036,8 +955,7 @@ public class Camera extends Activity implements View.OnClickListener, restartPreview(); - if (mPreferences.getBoolean("pref_camera_recordlocation_key", false)) - startReceivingLocationUpdates(); + if (mRecordLocation) startReceivingLocationUpdates(); updateFocusIndicator(); @@ -1049,78 +967,10 @@ public class Camera extends Activity implements View.OnClickListener, } } - private ImageManager.DataLocation dataLocation() { + private static ImageManager.DataLocation dataLocation() { return ImageManager.DataLocation.EXTERNAL; } - private static final int BUFSIZE = 4096; - - // Stores the thumbnail and URI of last-picture-taken to SD card, so we can - // load it the next time the Camera app starts. - private void storeLastThumb() { - if (mLastPictureUri != null && mLastPictureThumb != null) { - try { - FileOutputStream f = new FileOutputStream(ImageManager.getLastThumbPath()); - try { - BufferedOutputStream b = new BufferedOutputStream(f, BUFSIZE); - try { - DataOutputStream d = new DataOutputStream(b); - try { - d.writeUTF(mLastPictureUri.toString()); - mLastPictureThumb.compress(Bitmap.CompressFormat.PNG, 100, d); - } finally { - d.close(); - b = null; - f = null; - } - } finally { - if (b != null) { - b.close(); - f = null; - } - } - } finally { - if (f != null) { - f.close(); - } - } - } catch (IOException e) { - } - } - } - - // Loads the thumbnail and URI of last-picture-taken from SD card. - private void loadLastThumb() { - try { - FileInputStream f = new FileInputStream(ImageManager.getLastThumbPath()); - try { - BufferedInputStream b = new BufferedInputStream(f, BUFSIZE); - try { - DataInputStream d = new DataInputStream(b); - try { - Uri lastUri = Uri.parse(d.readUTF()); - Bitmap lastThumb = BitmapFactory.decodeStream(d); - setLastPictureThumb(lastThumb, lastUri); - } finally { - d.close(); - b = null; - f = null; - } - } finally { - if (b != null) { - b.close(); - f = null; - } - } - } finally { - if (f != null) { - f.close(); - } - } - } catch (IOException e) { - } - } - @Override public void onStop() { keep(); @@ -1153,7 +1003,10 @@ public class Camera extends Activity implements View.OnClickListener, mFocusToneGenerator = null; } - storeLastThumb(); + if (!mIsImageCaptureIntent) { + mThumbController.storeData(ImageManager.getLastImageThumbPath()); + } + if (mStorageHint != null) { mStorageHint.cancel(); mStorageHint = null; @@ -1347,19 +1200,6 @@ 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, @@ -1371,12 +1211,10 @@ public class Camera extends Activity implements View.OnClickListener, 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); + Uri uri = image.fullSizeImageUri(); + mThumbController.setData(uri, image.miniThumbBitmap()); } else { - mLastPictureUri = null; + mThumbController.setData(null, null); } list.deactivate(); } @@ -1396,21 +1234,12 @@ 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 (!isImageCaptureIntent() && !isLastPictureValid()) { + if (!mIsImageCaptureIntent && !mThumbController.isUriValid()) { updateLastImage(); } - if (mShouldShowLastPictureButton) { - mShouldShowLastPictureButton = false; - mLastPictureButton.setVisibility(View.VISIBLE); - Animation a = mShowLastPictureButtonAnimation; - a.setDuration(500); - mLastPictureButton.setAnimation(a); - } - - if (mShouldTransitionThumbnails) { - mShouldTransitionThumbnails = false; - mThumbnailTransition.startTransition(500); + if (!mIsImageCaptureIntent) { + mThumbController.updateDisplayIfNeeded(); } } @@ -1492,8 +1321,7 @@ public class Camera extends Activity implements View.OnClickListener, } catch (InterruptedException ex) { // } - if (mPreviewing) - break; + if (mPreviewing) break; int delay = (int) (SystemClock.elapsedRealtime() - wallTimeStart) / 1000; if (delay >= next_warning) { @@ -1553,8 +1381,8 @@ public class Camera extends Activity implements View.OnClickListener, } private void viewLastImage() { - Uri targetUri = mLastPictureUri; - if (targetUri != null && isLastPictureValid()) { + if (mThumbController.isUriValid()) { + Uri targetUri = mThumbController.getUri(); targetUri = targetUri.buildUpon(). appendQueryParameter("bucketId", ImageManager.CAMERA_IMAGE_BUCKET_ID).build(); Intent intent = new Intent(Intent.ACTION_VIEW, targetUri); @@ -1637,16 +1465,12 @@ public class Camera extends Activity implements View.OnClickListener, } private Location getCurrentLocation() { - Location l = null; - // go in best to worst order for (int i = 0; i < mLocationListeners.length; i++) { - l = mLocationListeners[i].current(); - if (l != null) - break; + Location l = mLocationListeners[i].current(); + if (l != null) return l; } - - return l; + return null; } @Override @@ -1703,7 +1527,7 @@ public class Camera extends Activity implements View.OnClickListener, } private void showPostCaptureAlert() { - if (isImageCaptureIntent()) { + if (mIsImageCaptureIntent) { mPostCaptureAlert.setVisibility(View.VISIBLE); int[] pickIds = {R.id.attach, R.id.cancel}; for(int id : pickIds) { @@ -1717,7 +1541,7 @@ public class Camera extends Activity implements View.OnClickListener, } private void hidePostCaptureAlert() { - if (isImageCaptureIntent()) { + if (mIsImageCaptureIntent) { mPostCaptureAlert.setVisibility(View.INVISIBLE); } } @@ -1726,7 +1550,7 @@ public class Camera extends Activity implements View.OnClickListener, public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - if (isImageCaptureIntent()) { + if (mIsImageCaptureIntent) { // No options menu for attach mode. return false; } else { diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index d7cfc2b..073b8db 100755 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -4197,8 +4197,13 @@ public class ImageManager { return bitmap; } - public static String getLastThumbPath() { + public static String getLastImageThumbPath() { return Environment.getExternalStorageDirectory().toString() + - "/DCIM/.thumbnails/camera_last_thumb"; + "/DCIM/.thumbnails/image_last_thumb"; + } + + public static String getLastVideoThumbPath() { + return Environment.getExternalStorageDirectory().toString() + + "/DCIM/.thumbnails/video_last_thumb"; } } diff --git a/src/com/android/camera/ThumbnailController.java b/src/com/android/camera/ThumbnailController.java new file mode 100644 index 0000000..c35c467 --- /dev/null +++ b/src/com/android/camera/ThumbnailController.java @@ -0,0 +1,233 @@ +/* + * 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 java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import android.content.ContentResolver; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.TransitionDrawable; +import android.net.Uri; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.ImageView; + +// A controller shows thumbnail picture on a button. The thumbnail picture +// corresponds to a URI of the original picture/video. The thumbnail bitmap +// and the URI can be saved to a file (and later loaded from it). +// +// public ThumbnailController(ImageView button) +// public void setData(Uri uri, Bitmap original) +// public void updateDisplayIfNeeded() +// public Uri getUri() +// public Bitmap getThumb() +// public boolean storeData(String filePath) +// public boolean loadData(String filePath) +// + +public class ThumbnailController { + private static final String TAG = "ThumbnailController"; + private ContentResolver mContentResolver; + private Uri mUri; + private Bitmap mThumb; + private ImageView mButton; + private Drawable mFrame; + private Drawable[] mThumbs; + private TransitionDrawable mThumbTransition; + private boolean mShouldAnimateThumb; + private Animation mShowButtonAnimation = new AlphaAnimation(0F, 1F); + private boolean mShouldAnimateButton; + + // The "frame" is a drawable we want to put on top of the thumbnail. + public ThumbnailController(ImageView button, Drawable frame, + ContentResolver contentResolver) { + mButton = button; + mFrame = frame; + mContentResolver = contentResolver; + mShowButtonAnimation.setDuration(500); + } + + public void setData(Uri uri, Bitmap original) { + // Make sure uri and original are consistently both null or both non-null. + if (uri == null || original == null) { + uri = null; + original = null; + } + mUri = uri; + updateThumb(original); + } + + public Uri getUri() { + return mUri; + } + + public Bitmap getThumb() { + return mThumb; + } + + private static final int BUFSIZE = 4096; + + // Stores the data from the specified file. + // Returns true for success. + public boolean storeData(String filePath) { + if (mUri == null) { + return false; + } + + FileOutputStream f = null; + BufferedOutputStream b = null; + DataOutputStream d = null; + try { + f = new FileOutputStream(filePath); + b = new BufferedOutputStream(f, BUFSIZE); + d = new DataOutputStream(b); + d.writeUTF(mUri.toString()); + mThumb.compress(Bitmap.CompressFormat.PNG, 100, d); + d.close(); + } catch (IOException e) { + return false; + } finally { + closeSilently(f); + closeSilently(b); + closeSilently(d); + } + return true; + } + + // Loads the data from the specified file. + // Returns true for success. + public boolean loadData(String filePath) { + FileInputStream f = null; + BufferedInputStream b = null; + DataInputStream d = null; + try { + f = new FileInputStream(filePath); + b = new BufferedInputStream(f, BUFSIZE); + d = new DataInputStream(b); + Uri uri = Uri.parse(d.readUTF()); + Bitmap thumb = BitmapFactory.decodeStream(d); + setData(uri, thumb); + d.close(); + } catch (IOException e) { + return false; + } finally { + closeSilently(f); + closeSilently(b); + closeSilently(d); + } + return true; + } + + private void closeSilently(Closeable c) { + if (c != null) { + try { + c.close(); + } catch (IOException e) { + // ignore + } + } + } + + public void updateDisplayIfNeeded() { + if (mUri == null) { + mButton.setVisibility(View.INVISIBLE); + return; + } + + if (mShouldAnimateButton) { + mButton.setVisibility(View.VISIBLE); + mButton.startAnimation(mShowButtonAnimation); + mShouldAnimateButton = false; + } + + if (mShouldAnimateThumb) { + mThumbTransition.startTransition(500); + mShouldAnimateThumb = false; + } + } + + private void updateThumb(Bitmap original) { + if (original == null) { + mThumb = null; + mThumbs = null; + return; + } + + // Make the mini-thumb size smaller than the button size so that the image corners + // don't peek out from the rounded corners of the frame_thumb graphic: + final int PADDING_WIDTH = 12; + final int PADDING_HEIGHT = 12; + LayoutParams layoutParams = mButton.getLayoutParams(); + final int miniThumbWidth = layoutParams.width - 2 * PADDING_WIDTH; + final int miniThumbHeight = layoutParams.height - 2 * PADDING_HEIGHT; + mThumb = ImageManager.extractMiniThumb( + original, miniThumbWidth, miniThumbHeight, false); + + Drawable[] vignetteLayers = new Drawable[2]; + vignetteLayers[0] = mFrame; + if (mThumbs == null) { + mThumbs = new Drawable[2]; + mThumbs[1] = new BitmapDrawable(mThumb); + vignetteLayers[1] = mThumbs[1]; + mShouldAnimateThumb = false; + } else { + mThumbs[0] = mThumbs[1]; + mThumbs[1] = new BitmapDrawable(mThumb); + mThumbTransition = new TransitionDrawable(mThumbs); + vignetteLayers[1] = mThumbTransition; + mShouldAnimateThumb = true; + } + + LayerDrawable mVignette = new LayerDrawable(vignetteLayers); + mVignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, + PADDING_WIDTH, PADDING_HEIGHT); + mButton.setImageDrawable(mVignette); + + if (mButton.getVisibility() != View.VISIBLE) { + mShouldAnimateButton = true; + } + } + + public boolean isUriValid() { + if (mUri == null) return false; + try { + mContentResolver.openFileDescriptor(mUri, "r").close(); + } catch (Exception ex) { + return false; + } + return true; + } +} diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 0d6e74d..7f1b010 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -19,14 +19,11 @@ package com.android.camera; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import android.app.Activity; -import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; @@ -34,21 +31,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.TransitionDrawable; import android.location.LocationManager; -import android.media.MediaMetadataRetriever; import android.media.MediaRecorder; import android.net.Uri; import android.os.Bundle; @@ -67,7 +53,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.View; -import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.MenuItem.OnMenuItemClickListener; @@ -84,8 +69,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, private static final boolean DEBUG = true; private static final boolean DEBUG_SUPPRESS_AUDIO_RECORDING = DEBUG && false; - private static final boolean DEBUG_DO_NOT_REUSE_MEDIA_RECORDER = DEBUG && true; - private static final boolean DEBUG_LOG_APP_LIFECYCLE = DEBUG && false; private static final int CLEAR_SCREEN_DELAY = 4; private static final int UPDATE_RECORD_TIME = 5; @@ -114,14 +97,13 @@ public class VideoCamera extends Activity implements View.OnClickListener, private static final float VIDEO_ASPECT_RATIO = 176.0f / 144.0f; VideoPreview mVideoPreview; SurfaceHolder mSurfaceHolder = null; - ImageView mBlackout = null; ImageView mVideoFrame; - Bitmap mVideoFrameBitmap; - private TransitionDrawable mThumbnailTransition; - private Drawable[] mThumbnails; - private boolean mShouldTransitionThumbnails; + + private boolean mIsVideoCaptureIntent; + // mLastPictureButton and mThumbController + // are non-null only if isVideoCaptureIntent() is true; private ImageView mLastPictureButton; - private Bitmap mLastPictureThumb; + private ThumbnailController mThumbController; private static final int MAX_RECORDING_DURATION_MS = 10 * 60 * 1000; @@ -268,9 +250,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, /** Called with the activity is first created. */ @Override public void onCreate(Bundle icicle) { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onCreate " + this.hashCode()); - } super.onCreate(icicle); mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); @@ -292,9 +271,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - mBlackout = (ImageView) findViewById(R.id.blackout); - mBlackout.setBackgroundDrawable(new ColorDrawable(0xFF000000)); - mPostPictureAlert = findViewById(R.id.post_picture_panel); int[] ids = new int[]{R.id.play, R.id.share, R.id.discard, @@ -307,8 +283,15 @@ public class VideoCamera extends Activity implements View.OnClickListener, mShutterButton.setOnShutterButtonListener(this); mRecordingTimeView = (TextView) findViewById(R.id.recording_time); mVideoFrame = (ImageView) findViewById(R.id.video_frame); - mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); - mLastPictureButton.setOnClickListener(this); + mIsVideoCaptureIntent = isVideoCaptureIntent(); + if (!mIsVideoCaptureIntent) { + mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); + mLastPictureButton.setOnClickListener(this); + Drawable frame = getResources().getDrawable(R.drawable.frame_thumbnail); + mThumbController = new ThumbnailController(mLastPictureButton, + frame, mContentResolver); + mThumbController.loadData(ImageManager.getLastVideoThumbPath()); + } } private void startShareVideoActivity() { @@ -359,7 +342,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, } case R.id.last_picture_button: { - stopPreviewAndShowAlert(); + stopVideoRecordingAndShowAlert(); break; } } @@ -373,15 +356,18 @@ public class VideoCamera extends Activity implements View.OnClickListener, switch (button.getId()) { case R.id.shutter_button: if (mMediaRecorderRecording) { - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { stopVideoRecordingAndShowAlert(); } else { - stopVideoRecordingAndShowThumbnail(); - doStartCaptureMode(); + stopVideoRecordingAndGetThumbnail(); + initializeVideo(); + } + } else if (isAlertVisible()) { + if (mIsVideoCaptureIntent) { + discardCurrentVideoAndStartPreview(); + } else { + hideAlertAndStartVideoRecording(); } - } else if (mVideoFrame.getVisibility() == View.VISIBLE) { - doStartCaptureMode(); - startVideoRecording(); } else { startVideoRecording(); } @@ -389,14 +375,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void doStartCaptureMode() { - if (isVideoCaptureIntent()) { - discardCurrentVideoAndStartPreview(); - } else { - hideVideoFrameAndStartPreview(); - } - } - private void doPlayCurrentVideo() { Log.e(TAG, "Playing current video: " + mCurrentVideoUri); Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri); @@ -409,7 +387,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, private void discardCurrentVideoAndStartPreview() { deleteCurrentVideo(); - hideVideoFrameAndStartPreview(); + hideAlertAndStartPreview(); } private OnScreenHint mStorageHint; @@ -452,9 +430,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, @Override public void onResume() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onResume " + this.hashCode()); - } super.onResume(); setScreenTimeoutLong(); @@ -477,40 +452,40 @@ public class VideoCamera extends Activity implements View.OnClickListener, } }, 200); - mBlackout.setVisibility(View.INVISIBLE); - if (mVideoFrameBitmap == null) { - initializeVideo(); - } else { - showVideoFrame(); - } + initializeVideo(); } @Override public void onStop() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onStop " + this.hashCode()); - } - stopVideoRecording(); setScreenTimeoutSystemDefault(); super.onStop(); } @Override protected void onPause() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onPause " + this.hashCode()); - } super.onPause(); - stopVideoRecording(); - hideVideoFrame(); + // This is similar to what mShutterButton.performClick() does, + // but not quite the same. + if (mMediaRecorderRecording) { + if (mIsVideoCaptureIntent) { + stopVideoRecordingAndShowAlert(); + } else { + stopVideoRecordingAndGetThumbnail(); + } + } else { + stopVideoRecording(); + } mPausing = true; unregisterReceiver(mReceiver); - mBlackout.setVisibility(View.VISIBLE); setScreenTimeoutSystemDefault(); + if (!mIsVideoCaptureIntent) { + mThumbController.storeData(ImageManager.getLastVideoThumbPath()); + } + if (mStorageHint != null) { mStorageHint.cancel(); mStorageHint = null; @@ -526,8 +501,8 @@ public class VideoCamera extends Activity implements View.OnClickListener, if (mMediaRecorderRecording) { mShutterButton.performClick(); return true; - } else if(isPostRecordingAlertVisible()) { - hideVideoFrameAndStartPreview(); + } else if(isAlertVisible()) { + hideAlertAndStartPreview(); return true; } break; @@ -565,6 +540,16 @@ public class VideoCamera extends Activity implements View.OnClickListener, } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + if (mPausing) { + // We're pausing, the screen is off and we already stopped + // video recording. We don't want to start the camera again + // in this case in order to conserve power. + // The fact that surfaceChanged is called _after_ an onPause appears + // to be legitimate since in that case the lockscreen always returns + // to portrait orientation possibly triggering the notification. + return; + } + stopVideoRecording(); initializeVideo(); } @@ -599,7 +584,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { // No options menu for attach mode. return false; } else { @@ -685,14 +670,18 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } + // initializeVideo() starts preview and prepare media recorder. // Returns false if initializeVideo fails private boolean initializeVideo() { Log.v(TAG, "initializeVideo"); - boolean isCaptureIntent = isVideoCaptureIntent(); + + // We will call initializeVideo() again when the alert is hidden. + if (isAlertVisible()) return false; + Intent intent = getIntent(); Bundle myExtras = intent.getExtras(); - if (isCaptureIntent && myExtras != null) { + if (mIsVideoCaptureIntent && myExtras != null) { Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); if (saveUri != null) { try { @@ -782,6 +771,15 @@ public class VideoCamera extends Activity implements View.OnClickListener, return false; } mMediaRecorderRecording = false; + + if (!mIsVideoCaptureIntent && !mThumbController.isUriValid()) { + updateLastVideo(); + } + + if (!mIsVideoCaptureIntent) { + mThumbController.updateDisplayIfNeeded(); + } + return true; } @@ -795,25 +793,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void restartPreview() { - if (DEBUG_DO_NOT_REUSE_MEDIA_RECORDER) { - Log.v(TAG, "DEBUG_DO_NOT_REUSE_MEDIA_RECORDER recreating mMediaRecorder."); - initializeVideo(); - } else { - try { - mMediaRecorder.prepare(); - } catch (IOException exception) { - Log.e(TAG, "prepare failed for " + mCameraVideoFilename); - releaseMediaRecorder(); - // TODO: add more exception handling logic here - } - } - if (mShouldTransitionThumbnails) { - mShouldTransitionThumbnails = false; - mThumbnailTransition.startTransition(500); - } - } - private int getIntPreference(String key, int defaultValue) { String s = mPreferences.getString(key, ""); int result = defaultValue; @@ -982,7 +961,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, mHandler.sendEmptyMessage(UPDATE_RECORD_TIME); setScreenTimeoutInfinite(); hideLastPictureButton(); - recycleVideoFrameBitmap(); } } @@ -993,37 +971,23 @@ public class VideoCamera extends Activity implements View.OnClickListener, mShutterButton.setImageDrawable(drawable); } - private void stopVideoRecordingAndShowThumbnail() { - Log.v(TAG, "stopVideoRecordingAndShowThumbnail"); - if (mMediaRecorderRecording) { - stopVideoRecording(); - acquireVideoFrame(); - setLastPictureThumb(mVideoFrameBitmap); - showLastPictureButton(); - } + private void stopVideoRecordingAndGetThumbnail() { + stopVideoRecording(); + acquireVideoThumb(); } private void stopVideoRecordingAndShowAlert() { - Log.v(TAG, "stopVideoRecordingAndShowAlert"); - if (mMediaRecorderRecording) { - stopVideoRecording(); - acquireVideoFrame(); - showVideoFrame(); - } - } - - private void stopPreviewAndShowAlert() { stopVideoRecording(); - showVideoFrame(); + showAlert(); } - private void showVideoFrame() { + private void showAlert() { int[] pickIds = {R.id.attach, R.id.cancel}; int[] normalIds = {R.id.gallery, R.id.share, R.id.discard}; int[] alwaysOnIds = {R.id.play}; int[] hideIds = pickIds; int[] connectIds = normalIds; - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { hideIds = normalIds; connectIds = pickIds; } @@ -1037,11 +1001,31 @@ public class VideoCamera extends Activity implements View.OnClickListener, connectAndFadeIn(connectIds); connectAndFadeIn(alwaysOnIds); hideLastPictureButton(); - mVideoFrame.setVisibility(View.VISIBLE); mPostPictureAlert.setVisibility(View.VISIBLE); + + // There are two cases we are here: + // (1) We are in a capture video intent, and we are reviewing the video + // we just taken. + // (2) The thumbnail button is clicked: we review the video associated + // with the thumbnail. + // For the second case, we copy the associated URI and filename to + // mCurrentVideoUri and mCurrentVideoFilename, so the video frame shown + // and the target for actions (play, delete, ...) will be correct. + + if (!mIsVideoCaptureIntent) { + mCurrentVideoUri = mThumbController.getUri(); + mCurrentVideoFilename = getDataPath(mCurrentVideoUri); + } + + String path = mCurrentVideoFilename; + if (path != null) { + Bitmap videoFrame = ImageManager.createVideoThumbnail(path); + mVideoFrame.setImageBitmap(videoFrame); + mVideoFrame.setVisibility(View.VISIBLE); + } } - private void hideVideoFrame() { + private void hideAlert() { mVideoFrame.setVisibility(View.INVISIBLE); mPostPictureAlert.setVisibility(View.INVISIBLE); showLastPictureButton(); @@ -1053,11 +1037,11 @@ public class VideoCamera extends Activity implements View.OnClickListener, view.setOnClickListener(this); Animation animation = new AlphaAnimation(0F, 1F); animation.setDuration(500); - view.setAnimation(animation); + view.startAnimation(animation); } } - private boolean isPostRecordingAlertVisible() { + private boolean isAlertVisible() { return mPostPictureAlert.getVisibility() == View.VISIBLE; } @@ -1130,82 +1114,71 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void hideVideoFrameAndStartPreview() { - hideVideoFrame(); - restartPreview(); + private void hideAlertAndStartPreview() { + hideAlert(); + initializeVideo(); } - private void acquireVideoFrame() { - recycleVideoFrameBitmap(); - mVideoFrameBitmap = ImageManager.createVideoThumbnail(mCurrentVideoFilename); - mVideoFrame.setImageBitmap(mVideoFrameBitmap); - Log.v(TAG, "acquireVideoFrame:" + mVideoFrameBitmap); + private void hideAlertAndStartVideoRecording() { + hideAlert(); + startVideoRecording(); } - //TODO: Refactor the code so that the following code is shared between - // VideoCamera.java and Camera.java - private static Bitmap makeRoundedCorner(Bitmap thumb, int rx, int ry) { - if (thumb == null) return null; - int width = thumb.getWidth(); - int height = thumb.getHeight(); - - Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(result); - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setStyle(Paint.Style.FILL); - canvas.drawRoundRect(new RectF(0, 0, width, height), rx, ry, paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(thumb, 0, 0, paint); - return result; + private void acquireVideoThumb() { + Bitmap videoFrame = ImageManager.createVideoThumbnail(mCurrentVideoFilename); + mThumbController.setData(mCurrentVideoUri, videoFrame); } - private void setLastPictureThumb(Bitmap videoFrame) { - - final int PADDING_WIDTH = 6; - final int PADDING_HEIGHT = 6; - LayoutParams layoutParams = mLastPictureButton.getLayoutParams(); - // Make the mini-thumbnail size smaller than the button size so that the image corners - // don't peek out from the rounded corners of the frame_thumbnail graphic: - final int miniThumbWidth = layoutParams.width - 2 * PADDING_WIDTH; - final int miniThumbHeight = layoutParams.height - 2 * PADDING_HEIGHT; - - Bitmap lastPictureThumb = ImageManager.extractMiniThumb(videoFrame, - miniThumbWidth, miniThumbHeight, false); - lastPictureThumb = makeRoundedCorner(lastPictureThumb, 3, 3); - - Drawable[] vignetteLayers = new Drawable[2]; - vignetteLayers[0] = getResources().getDrawable(R.drawable.frame_thumbnail); - if (mThumbnails == null) { - mThumbnails = new Drawable[2]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - vignetteLayers[1] = mThumbnails[1]; - } else { - mThumbnails[0] = mThumbnails[1]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - mThumbnailTransition = new TransitionDrawable(mThumbnails); - mShouldTransitionThumbnails = true; - vignetteLayers[1] = mThumbnailTransition; + private void showLastPictureButton() { + if (!mIsVideoCaptureIntent) { + mLastPictureButton.setVisibility(View.VISIBLE); } + } - LayerDrawable vignette = new LayerDrawable(vignetteLayers); - vignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, - PADDING_WIDTH, PADDING_HEIGHT); - mLastPictureButton.setImageDrawable(vignette); + private void hideLastPictureButton() { + if (!mIsVideoCaptureIntent) { + mLastPictureButton.setVisibility(View.INVISIBLE); + } } - private void showLastPictureButton() { - mLastPictureButton.setVisibility(View.VISIBLE); + private static ImageManager.DataLocation dataLocation() { + return ImageManager.DataLocation.EXTERNAL; } - private void hideLastPictureButton() { - mLastPictureButton.setVisibility(View.INVISIBLE); + private void updateLastVideo() { + ImageManager.IImageList list = ImageManager.instance().allImages( + this, + mContentResolver, + dataLocation(), + ImageManager.INCLUDE_VIDEOS, + ImageManager.SORT_ASCENDING, + ImageManager.CAMERA_IMAGE_BUCKET_ID); + int count = list.getCount(); + if (count > 0) { + ImageManager.IImage image = list.getImageAt(count-1); + Uri uri = image.fullSizeImageUri(); + mThumbController.setData(uri, image.miniThumbBitmap()); + } else { + mThumbController.setData(null, null); + } + list.deactivate(); } - private void recycleVideoFrameBitmap() { - if (mVideoFrameBitmap != null) { - mVideoFrame.setImageDrawable(null); - mVideoFrameBitmap.recycle(); - mVideoFrameBitmap = null; + private static final String[] DATA_PATH_PROJECTION = new String[] { + "_data" + }; + + private String getDataPath(Uri uri) { + Cursor c = null; + try { + c = mContentResolver.query(uri, DATA_PATH_PROJECTION, null, null, null); + if (c != null && c.moveToFirst()) { + return c.getString(0); + } else { + return null; + } + } finally { + if (c != null) c.close(); } } } diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java index 2e777fd..1376172 100644 --- a/src/com/android/camera/ViewImage.java +++ b/src/com/android/camera/ViewImage.java @@ -201,6 +201,17 @@ public class ViewImage extends Activity implements View.OnClickListener 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 setupZoomButtonController(View rootView) { mGestureDetector = new GestureDetector(this, new MyGestureListener()); mZoomButtonsController = new ZoomButtonsController(rootView); |