diff options
-rw-r--r-- | res/layout/photo_module.xml | 2 | ||||
-rw-r--r-- | res/menu/operations.xml | 67 | ||||
-rw-r--r-- | res/values/styles.xml | 3 | ||||
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 130 | ||||
-rw-r--r-- | src/com/android/camera/PhotoController.java | 18 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 248 | ||||
-rw-r--r-- | src/com/android/camera/PhotoUI.java | 50 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 57 | ||||
-rw-r--r-- | src/com/android/camera/data/CameraDataAdapter.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/data/FixedFirstDataAdapter.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/ui/FilmStripView.java | 1 |
11 files changed, 358 insertions, 230 deletions
diff --git a/res/layout/photo_module.xml b/res/layout/photo_module.xml index 390863a71..f5525b832 100644 --- a/res/layout/photo_module.xml +++ b/res/layout/photo_module.xml @@ -48,4 +48,4 @@ <include layout="@layout/camera_controls" android:layout_gravity="center" style="@style/CameraControls"/> -</merge>
\ No newline at end of file +</merge> diff --git a/res/menu/operations.xml b/res/menu/operations.xml new file mode 100644 index 000000000..bcebbb47b --- /dev/null +++ b/res/menu/operations.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2013 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. +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/action_share" + android:icon="@drawable/ic_menu_share_holo_light" + android:title="@string/share" + android:visible="false" + android:actionProviderClass="android.widget.ShareActionProvider" + android:showAsAction="ifRoom"> + </item> + <item android:id="@+id/action_delete" + android:icon="@drawable/ic_menu_trash_holo_light" + android:title="@string/delete" + android:visible="false" + android:showAsAction="never" /> + <item android:id="@+id/action_edit" + android:title="@string/edit" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/action_trim" + android:title="@string/trim_action" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/action_mute" + android:title="@string/mute_action" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/action_rotate_ccw" + android:showAsAction="never" + android:visible="false" + android:title="@string/rotate_left" /> + <item android:id="@+id/action_rotate_cw" + android:showAsAction="never" + android:visible="false" + android:title="@string/rotate_right" /> + <item android:id="@+id/action_crop" + android:title="@string/crop_action" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/action_setas" + android:title="@string/set_image" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/action_details" + android:icon="@drawable/ic_menu_info_details" + android:title="@string/details" + android:visible="false" + android:showAsAction="never" /> + <item android:id="@+id/action_show_on_map" + android:title="@string/show_on_map" + android:showAsAction="never" + android:visible="false" /> +</menu> diff --git a/res/values/styles.xml b/res/values/styles.xml index dede2391b..946329070 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -55,6 +55,9 @@ </style> <style name="Theme.Camera" parent="Theme.CameraBase"> + <item name="android:windowActionBar">false</item> + <item name="android:windowTitleSize">0dp</item> + <item name="android:windowActionBarOverlay">true</item> <item name="android:windowBackground">@android:color/black</item> <item name="android:colorBackground">@android:color/black</item> <item name="android:colorBackgroundCacheHint">@android:color/black</item> diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 82d10a98b..099b5035f 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -37,6 +37,9 @@ import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.OrientationEventListener; import android.view.View; import android.view.ViewGroup; @@ -77,6 +80,19 @@ public class CameraActivity extends Activity // panorama. If the extra is not set, it is in the normal camera mode. public static final String SECURE_CAMERA_EXTRA = "secure_camera"; + // Supported operations at FilmStripView. Different data has different + // set of supported operations. + private static final int SUPPORT_DELETE = 1 << 0; + private static final int SUPPORT_ROTATE = 1 << 1; + private static final int SUPPORT_INFO = 1 << 2; + private static final int SUPPORT_CROP = 1 << 3; + private static final int SUPPORT_SETAS = 1 << 4; + private static final int SUPPORT_EDIT = 1 << 5; + private static final int SUPPORT_TRIM = 1 << 6; + private static final int SUPPORT_MUTE = 1 << 7; + private static final int SUPPORT_SHOW_ON_MAP = 1 << 8; + private static final int SUPPORT_ALL = 0xffffffff; + /** This data adapter is used by FilmStirpView. */ private LocalDataAdapter mDataAdapter; /** This data adapter represents the real local camera data. */ @@ -104,6 +120,7 @@ public class CameraActivity extends Activity private PanoramaViewHelper mPanoramaViewHelper; private CameraPreviewData mCameraPreviewData; private ActionBar mActionBar; + private Menu mActionBarMenu; private class MyOrientationEventListener extends OrientationEventListener { @@ -195,6 +212,9 @@ public class CameraActivity extends Activity hidePanoStitchingProgress(); return; } + int type = currentData.getLocalDataType(dataID); + updateActionBarMenu(type); + Uri contentUri = currentData.getContentUri(); if (contentUri == null) { hidePanoStitchingProgress(); @@ -223,6 +243,64 @@ public class CameraActivity extends Activity mBottomProgress.setProgress(progress); } + /** + * According to the data type, make the menu items for supported operations + * visible. + * @param type : the data type for the current local data. + */ + private void updateActionBarMenu(int type) { + if (mActionBarMenu == null) { + return; + } + + int supported = 0; + switch (type) { + case LocalData.LOCAL_IMAGE: + supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO + | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT + | SUPPORT_SHOW_ON_MAP; + break; + case LocalData.LOCAL_VIDEO: + supported |= SUPPORT_DELETE | SUPPORT_INFO | SUPPORT_TRIM + | SUPPORT_MUTE; + break; + case LocalData.LOCAL_PHOTO_SPHERE: + supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO + | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT + | SUPPORT_SHOW_ON_MAP; + break; + default: + break; + } + + setMenuItemVisible(mActionBarMenu, R.id.action_delete, + (supported & SUPPORT_DELETE) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_rotate_ccw, + (supported & SUPPORT_ROTATE) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_rotate_cw, + (supported & SUPPORT_ROTATE) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_crop, + (supported & SUPPORT_CROP) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_trim, + (supported & SUPPORT_TRIM) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_mute, + (supported & SUPPORT_MUTE) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_setas, + (supported & SUPPORT_SETAS) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map, + (supported & SUPPORT_SHOW_ON_MAP) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_edit, + (supported & SUPPORT_EDIT) != 0); + setMenuItemVisible(mActionBarMenu, R.id.action_details, + (supported & SUPPORT_INFO) != 0); + } + + private void setMenuItemVisible(Menu menu, int itemId, boolean visible) { + MenuItem item = menu.findItem(itemId); + if (item != null) + item.setVisible(visible); + } + private Runnable mDeletionRunnable = new Runnable() { @Override public void run() { @@ -324,8 +402,57 @@ public class CameraActivity extends Activity } @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu items for use in the action bar + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.operations, menu); + mActionBarMenu = menu; + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_delete: + // TODO: add the functionality. + return true; + case R.id.action_edit: + // TODO: add the functionality. + return true; + case R.id.action_trim: + // TODO: add the functionality. + return true; + case R.id.action_mute: + // TODO: add the functionality. + return true; + case R.id.action_rotate_ccw: + // TODO: add the functionality. + return true; + case R.id.action_rotate_cw: + // TODO: add the functionality. + return true; + case R.id.action_crop: + // TODO: add the functionality. + return true; + case R.id.action_setas: + // TODO: add the functionality. + return true; + case R.id.action_details: + // TODO: add the functionality. + return true; + case R.id.action_show_on_map: + // TODO: add the functionality. + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override public void onCreate(Bundle state) { super.onCreate(state); + getWindow().requestFeature(Window.FEATURE_ACTION_BAR); setContentView(R.layout.camera_filmstrip); mActionBar = getActionBar(); // Hide action bar first since we are in full screen mode first. @@ -400,6 +527,7 @@ public class CameraActivity extends Activity if (!mSecureCamera) { mDataAdapter = mWrappedDataAdapter; + mFilmStripView.setDataAdapter(mDataAdapter); mDataAdapter.requestLoad(getContentResolver()); } else { // Put a lock placeholder as the last image by setting its date to 0. @@ -414,8 +542,8 @@ public class CameraActivity extends Activity 0, 0)); // Flush out all the original data. mDataAdapter.flush(); + mFilmStripView.setDataAdapter(mDataAdapter); } - mFilmStripView.setDataAdapter(mDataAdapter); } private void setRotationAnimation() { diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index bc824d917..f32d2d967 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -16,7 +16,6 @@ package com.android.camera; -import android.view.SurfaceHolder; import android.view.View; import com.android.camera.ShutterButton.OnShutterButtonListener; @@ -53,8 +52,6 @@ public interface PhotoController extends OnShutterButtonListener { public void onSingleTapUp(View view, int x, int y); - public void onSurfaceCreated(SurfaceHolder holder); - public void onCountDownFinished(); public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight); @@ -62,4 +59,19 @@ public interface PhotoController extends OnShutterButtonListener { public void updateCameraOrientation(); public void enableRecordingLocation(boolean enable); + + /** + * This is the callback when the UI or buffer holder for camera preview, + * such as {@link android.graphics.SurfaceTexture}, is ready to be used. + * The controller can start the camera preview after or in this callback. + */ + public void onPreviewUIReady(); + + + /** + * This is the callback when the UI or buffer holder for camera preview, + * such as {@link android.graphics.SurfaceTexture}, is being destroyed. + * The controller should try to stop the preview in this callback. + */ + public void onPreviewUIDestroyed(); } diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 8d68320bf..1b0432f51 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -16,15 +16,6 @@ package com.android.camera; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Formatter; -import java.util.List; - import android.annotation.TargetApi; import android.app.Activity; import android.content.ContentProviderClient; @@ -46,7 +37,6 @@ import android.location.Location; import android.media.CameraProfile; import android.net.Uri; import android.os.Bundle; -import android.os.ConditionVariable; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -56,7 +46,6 @@ import android.provider.MediaStore; import android.util.Log; import android.view.KeyEvent; import android.view.OrientationEventListener; -import android.view.SurfaceHolder; import android.view.View; import android.view.WindowManager; @@ -65,10 +54,10 @@ import com.android.camera.CameraManager.CameraAFMoveCallback; import com.android.camera.CameraManager.CameraPictureCallback; import com.android.camera.CameraManager.CameraProxy; import com.android.camera.CameraManager.CameraShutterCallback; -import com.android.camera.util.ApiHelper; import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; import com.android.camera.ui.PopupManager; import com.android.camera.ui.RotateTextToast; +import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; import com.android.camera.util.UsageStatistics; import com.android.camera2.R; @@ -76,6 +65,14 @@ import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.exif.ExifTag; import com.android.gallery3d.exif.Rational; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + public class PhotoModule implements CameraModule, PhotoController, @@ -95,14 +92,12 @@ public class PhotoModule private static final int FIRST_TIME_INIT = 2; private static final int CLEAR_SCREEN_DELAY = 3; private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4; - private static final int CHECK_DISPLAY_ROTATION = 5; - private static final int SHOW_TAP_TO_FOCUS_TOAST = 6; - private static final int SWITCH_CAMERA = 7; - private static final int SWITCH_CAMERA_START_ANIMATION = 8; - private static final int CAMERA_OPEN_DONE = 9; - private static final int START_PREVIEW_DONE = 10; - private static final int OPEN_CAMERA_FAIL = 11; - private static final int CAMERA_DISABLED = 12; + private static final int SHOW_TAP_TO_FOCUS_TOAST = 5; + private static final int SWITCH_CAMERA = 6; + private static final int SWITCH_CAMERA_START_ANIMATION = 7; + private static final int CAMERA_OPEN_DONE = 8; + private static final int OPEN_CAMERA_FAIL = 9; + private static final int CAMERA_DISABLED = 10; // The subset of parameters we need to update in setCameraParameters(). private static final int UPDATE_PARAM_INITIALIZE = 1; @@ -143,7 +138,7 @@ public class PhotoModule private boolean mMeteringAreaSupported; private boolean mAeLockSupported; private boolean mAwbLockSupported; - private boolean mContinousFocusSupported; + private boolean mContinuousFocusSupported; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -169,10 +164,6 @@ public class PhotoModule } }; - private final StringBuilder mBuilder = new StringBuilder(); - private final Formatter mFormatter = new Formatter(mBuilder); - private final Object[] mFormatterArgs = new Object[1]; - /** * An unpublished intent flag requesting to return as soon as capturing * is completed. @@ -245,8 +236,8 @@ public class PhotoModule private float[] mR = new float[16]; private int mHeading = -1; - CameraStartUpThread mCameraStartUpThread; - ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); + // True if all the parameters needed to start preview is ready. + private boolean mCameraPreviewParamsReady = false; private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @@ -258,46 +249,22 @@ public class PhotoModule } }; - // The purpose is not to block the main thread in onCreate and onResume. - private class CameraStartUpThread extends Thread { - private volatile boolean mCancelled; - - public void cancel() { - mCancelled = true; - interrupt(); - } - - public boolean isCanceled() { - return mCancelled; + private void checkDisplayRotation() { + // Set the display orientation if display rotation has changed. + // Sometimes this happens when the device is held upside + // down and camera app is opened. Rotation animation will + // take some time and the rotation value we have got may be + // wrong. Framework does not have a callback for this now. + if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) { + setDisplayOrientation(); } - - @Override - public void run() { - try { - // We need to check whether the activity is paused before long - // operations to ensure that onPause() can be done ASAP. - if (mCancelled) return; - mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - // Wait until all the initialization needed by startPreview are - // done. - mStartPreviewPrerequisiteReady.block(); - - initializeCapabilities(); - if (mFocusManager == null) initializeFocusManager(); - if (mCancelled) return; - setCameraParameters(UPDATE_PARAM_ALL); - mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); - if (mCancelled) return; - startPreview(); - mHandler.sendEmptyMessage(START_PREVIEW_DONE); - mOnResumeTime = SystemClock.uptimeMillis(); - mHandler.sendEmptyMessage(CHECK_DISPLAY_ROTATION); - } catch (CameraHardwareException e) { - mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL); - } catch (CameraDisabledException e) { - mHandler.sendEmptyMessage(CAMERA_DISABLED); - } + if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + checkDisplayRotation(); + } + }, 100); } } @@ -330,21 +297,6 @@ public class PhotoModule break; } - case CHECK_DISPLAY_ROTATION: { - // Set the display orientation if display rotation has changed. - // Sometimes this happens when the device is held upside - // down and camera app is opened. Rotation animation will - // take some time and the rotation value we have got may be - // wrong. Framework does not have a callback for this now. - if (CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation) { - setDisplayOrientation(); - } - if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - break; - } - case SHOW_TAP_TO_FOCUS_TOAST: { showTapToFocusToast(); break; @@ -366,13 +318,7 @@ public class PhotoModule break; } - case START_PREVIEW_DONE: { - onPreviewStarted(); - break; - } - case OPEN_CAMERA_FAIL: { - mCameraStartUpThread = null; mOpenCameraFail = true; CameraUtil.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); @@ -380,7 +326,6 @@ public class PhotoModule } case CAMERA_DISABLED: { - mCameraStartUpThread = null; mCameraDisabled = true; CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); @@ -400,11 +345,6 @@ public class PhotoModule mContentResolver = mActivity.getContentResolver(); - // To reduce startup time, open the camera and start the preview in - // another thread. - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - // Surface texture is from camera screen nail and startPreview needs it. // This must be done before startPreview. mIsImageCaptureIntent = isImageCaptureIntent(); @@ -413,9 +353,6 @@ public class PhotoModule CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); // we need to reset exposure for the preview resetExposureCompensation(); - // Starting the preview needs preferences, camera screen nail, and - // focus area indicator. - mStartPreviewPrerequisiteReady.open(); initializeControlByIntent(); mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); @@ -431,7 +368,6 @@ public class PhotoModule } private void onPreviewStarted() { - mCameraStartUpThread = null; setCameraState(IDLE); startFaceDetection(); locationFirstRun(); @@ -458,6 +394,20 @@ public class PhotoModule : RecordLocationPreference.VALUE_OFF); } + @Override + public void onPreviewUIReady() { + startPreview(); + } + + @Override + public void onPreviewUIDestroyed() { + if (mCameraDevice == null) { + return; + } + mCameraDevice.setPreviewTexture(null); + stopPreview(); + } + private void setLocationPreference(String value) { mPreferences.edit() .putString(CameraSettings.KEY_RECORD_LOCATION, value) @@ -607,20 +557,6 @@ public class PhotoModule keepMediaProviderInstance(); } - @Override - public void onSurfaceCreated(SurfaceHolder holder) { - // Do not access the camera if camera start up thread is not finished. - if (mCameraDevice == null || mCameraStartUpThread != null) - return; - - mCameraDevice.setPreviewDisplay(holder); - // This happens when onConfigurationChanged arrives, surface has been - // destroyed, and there is no onFullScreenChanged. - if (mCameraState == PREVIEW_STOPPED) { - setupPreview(); - } - } - private void showTapToFocusToastIfNeeded() { // Show the tap to focus toast if this is the first start. if (mFocusAreaSupported && @@ -851,7 +787,6 @@ public class PhotoModule private static class NamedImages { private ArrayList<NamedEntity> mQueue; - private boolean mStop; private NamedEntity mNamedEntity; public NamedImages() { @@ -1208,18 +1143,37 @@ public class PhotoModule mPaused = false; } + private void prepareCamera() { + try { + // We need to check whether the activity is paused before long + // operations to ensure that onPause() can be done ASAP. + mCameraDevice = CameraUtil.openCamera(mActivity, mCameraId); + mParameters = mCameraDevice.getParameters(); + + initializeCapabilities(); + if (mFocusManager == null) initializeFocusManager(); + setCameraParameters(UPDATE_PARAM_ALL); + mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); + mCameraPreviewParamsReady = true; + startPreview(); + mOnResumeTime = SystemClock.uptimeMillis(); + checkDisplayRotation(); + } catch (CameraHardwareException e) { + mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL); + } catch (CameraDisabledException e) { + mHandler.sendEmptyMessage(CAMERA_DISABLED); + } + } + + @Override public void onResumeAfterSuper() { if (mOpenCameraFail || mCameraDisabled) return; mJpegPictureCallbackTime = 0; mZoomValue = 0; - // Start the preview if it is not started. - if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) { - resetExposureCompensation(); - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - } + resetExposureCompensation(); + prepareCamera(); // If first time initialization is not finished, put it in the // message queue. @@ -1246,19 +1200,6 @@ public class PhotoModule } } - void waitCameraStartUpThread() { - try { - if (mCameraStartUpThread != null) { - mCameraStartUpThread.cancel(); - mCameraStartUpThread.join(); - mCameraStartUpThread = null; - setCameraState(IDLE); - } - } catch (InterruptedException e) { - // ignore - } - } - @Override public void onPauseBeforeSuper() { mPaused = true; @@ -1275,9 +1216,6 @@ public class PhotoModule @Override public void onPauseAfterSuper() { - // Wait the camera start up thread to finish. - waitCameraStartUpThread(); - // When camera is started from secure lock screen for the first time // after screen on, the activity gets onCreate->onResume->onPause->onResume. // To reduce the latency, keep the camera for a short time so it does @@ -1302,16 +1240,8 @@ public class PhotoModule // a picture, we just clear it in onPause. mJpegImageData = null; - // Remove the messages in the event queue. - mHandler.removeMessages(SETUP_PREVIEW); - mHandler.removeMessages(FIRST_TIME_INIT); - mHandler.removeMessages(CHECK_DISPLAY_ROTATION); - mHandler.removeMessages(SWITCH_CAMERA); - mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION); - mHandler.removeMessages(CAMERA_OPEN_DONE); - mHandler.removeMessages(START_PREVIEW_DONE); - mHandler.removeMessages(OPEN_CAMERA_FAIL); - mHandler.removeMessages(CAMERA_DISABLED); + // Remove the messages and runnables in the queue. + mHandler.removeCallbacksAndMessages(null); closeCamera(); @@ -1503,17 +1433,26 @@ public class PhotoModule } } - // Only called by UI thread. + /** Only called by UI thread. */ private void setupPreview() { mFocusManager.resetTouchFocus(); startPreview(); - setCameraState(IDLE); - startFaceDetection(); } - // This can be called by UI Thread or CameraStartUpThread. So this should - // not modify the views. + // This can only be called by UI Thread. private void startPreview() { + if (mPaused) { + return; + } + SurfaceTexture st = mUI.getSurfaceTexture(); + if (st == null) { + Log.w(TAG, "startPreview: surfaceTexture is not ready."); + return; + } + if (!mCameraPreviewParamsReady) { + Log.w(TAG, "startPreview: parameters for preview is not ready."); + return; + } mCameraDevice.setErrorCallback(mErrorCallback); // ICS camera frameworks has a bug. Face detection state is not cleared @@ -1533,15 +1472,12 @@ public class PhotoModule } setCameraParameters(UPDATE_PARAM_ALL); // Let UI set its expected aspect ratio - mUI.setPreviewSize(mParameters.getPreviewSize()); - Object st = mUI.getSurfaceTexture(); - if (st != null) { - mCameraDevice.setPreviewTexture((SurfaceTexture) st); - } + mCameraDevice.setPreviewTexture(st); Log.v(TAG, "startPreview"); mCameraDevice.startPreview(); mFocusManager.onPreviewStarted(); + onPreviewStarted(); if (mSnapshotOnIdle) { mHandler.post(mDoSnapRunnable); @@ -1739,7 +1675,7 @@ public class PhotoModule mFocusManager.overrideFocusMode(mParameters.getFocusMode()); } - if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { + if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { updateAutoFocusMoveCallback(); } } @@ -1889,7 +1825,7 @@ public class PhotoModule mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams); mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams); mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams); - mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains( + mContinuousFocusSupported = mInitialParams.getSupportedFocusModes().contains( CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE); } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index f5748ba3d..4b353f1cf 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -79,7 +79,7 @@ public class PhotoUI implements PieListener, private PreviewGestures mGestures; private View mRootView; - private Object mSurfaceTexture; + private SurfaceTexture mSurfaceTexture; private PopupWindow mPopup; private ShutterButton mShutterButton; @@ -119,7 +119,6 @@ public class PhotoUI implements PieListener, private TextureView mTextureView; private Matrix mMatrix = null; private float mAspectRatio = 4f / 3f; - private final Object mLock = new Object(); private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -197,7 +196,7 @@ public class PhotoUI implements PieListener, mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); mSwitcher.setCurrentIndex(CameraSwitcher.PHOTO_MODULE_INDEX); - mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); + mSwitcher.setSwitchListener(mActivity); mMenuButton = mRootView.findViewById(R.id.menu); if (ApiHelper.HAS_FACE_DETECTION) { ViewStub faceViewStub = (ViewStub) mRootView @@ -205,8 +204,7 @@ public class PhotoUI implements PieListener, if (faceViewStub != null) { faceViewStub.inflate(); mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); - setSurfaceTextureSizeChangedListener( - (SurfaceTextureSizeChangedListener) mFaceView); + setSurfaceTextureSizeChangedListener(mFaceView); } } mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); @@ -222,21 +220,6 @@ public class PhotoUI implements PieListener, mSurfaceTextureSizeListener = listener; } - public void setPreviewSize(Size size) { - int width = size.width; - int height = size.height; - if (width == 0 || height == 0) { - Log.w(TAG, "Preview size should not be 0."); - return; - } - if (width > height) { - mAspectRatio = (float) width / height; - } else { - mAspectRatio = (float) height / width; - } - mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); - } - private void setTransformMatrix(int width, int height) { mMatrix = mTextureView.getTransform(mMatrix); int orientation = CameraUtil.getDisplayRotation(mActivity); @@ -269,26 +252,28 @@ public class PhotoUI implements PieListener, mTextureView.setTransform(mMatrix); } + @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - synchronized (mLock) { - mSurfaceTexture = surface; - mLock.notifyAll(); - } + Log.v(TAG, "SurfaceTexture ready."); + mSurfaceTexture = surface; + mController.onPreviewUIReady(); } + @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Ignored, Camera does all the work for us } + @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mSurfaceTexture = null; - mController.stopPreview(); - Log.w(TAG, "surfaceTexture is destroyed"); + mController.onPreviewUIDestroyed(); + Log.w(TAG, "SurfaceTexture destroyed"); return true; } public void onSurfaceTextureUpdated(SurfaceTexture surface) { - // Invoked every time there's a new Camera preview frame + // Do nothing. } public View getRootView() { @@ -707,16 +692,7 @@ public class PhotoUI implements PieListener, mActivity.setSwipingEnabled(enable); } - public Object getSurfaceTexture() { - synchronized (mLock) { - if (mSurfaceTexture == null) { - try { - mLock.wait(); - } catch (InterruptedException e) { - Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); - } - } - } + public SurfaceTexture getSurfaceTexture() { return mSurfaceTexture; } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index b28b66ffd..0a6faba6a 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -49,7 +49,6 @@ import android.provider.MediaStore.Video; import android.util.Log; import android.view.KeyEvent; import android.view.OrientationEventListener; -import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.widget.Toast; @@ -177,7 +176,6 @@ public class VideoModule implements CameraModule, private LocationManager mLocationManager; private OrientationManager mOrientationManager; - private Surface mSurface; private int mPendingSwitchCameraId; private boolean mOpenCameraFail; private boolean mCameraDisabled; @@ -420,26 +418,35 @@ public class VideoModule implements CameraModule, mOrientation).show(); return; } + takeASnapshot(); + } - MediaSaveService s = mActivity.getMediaSaveService(); - if (mPaused || mSnapshotInProgress || effectsActive() || s == null || s.isQueueFull()) { - return; - } + private void takeASnapshot() { + // Only take snapshots if video snapshot is supported by device + if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { + if (!mMediaRecorderRecording || mPaused || mSnapshotInProgress || effectsActive()) { + return; + } + MediaSaveService s = mActivity.getMediaSaveService(); + if (s == null || s.isQueueFull()) { + return; + } - // Set rotation and gps data. - int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation); - mParameters.setRotation(rotation); - Location loc = mLocationManager.getCurrentLocation(); - CameraUtil.setGpsParameters(mParameters, loc); - mCameraDevice.setParameters(mParameters); + // Set rotation and gps data. + int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation); + mParameters.setRotation(rotation); + Location loc = mLocationManager.getCurrentLocation(); + CameraUtil.setGpsParameters(mParameters, loc); + mCameraDevice.setParameters(mParameters); - Log.v(TAG, "Video snapshot start"); - mCameraDevice.takePicture(mHandler, - null, null, null, new JpegPictureCallback(loc)); - showVideoSnapshotUI(true); - mSnapshotInProgress = true; - UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, - UsageStatistics.ACTION_CAPTURE_DONE, "VideoSnapshot"); + Log.v(TAG, "Video snapshot start"); + mCameraDevice.takePicture(mHandler, + null, null, null, new JpegPictureCallback(loc)); + showVideoSnapshotUI(true); + mSnapshotInProgress = true; + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + UsageStatistics.ACTION_CAPTURE_DONE, "VideoSnapshot"); + } } @Override @@ -833,7 +840,6 @@ public class VideoModule implements CameraModule, CameraUtil.showErrorAndFinish(mActivity, R.string.camera_disabled); } } - } private void onPreviewStarted() { @@ -1190,9 +1196,6 @@ public class VideoModule implements CameraModule, // If the mCameraDevice is null, then this activity is going to finish if (mCameraDevice == null) return; - boolean inLandscape = (mActivity.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE); - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; mEffectsDisplayResult = false; @@ -1527,14 +1530,6 @@ public class VideoModule implements CameraModule, mUI.showTimeLapseUI(false); } - private void hideAlert() { - mUI.enableCameraControls(true); - mUI.hideReviewUI(); - if (mCaptureTimeLapse) { - mUI.showTimeLapseUI(true); - } - } - private boolean stopVideoRecording() { Log.v(TAG, "stopVideoRecording"); mUI.setSwipingEnabled(true); diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java index c265e397e..2cdb2c172 100644 --- a/src/com/android/camera/data/CameraDataAdapter.java +++ b/src/com/android/camera/data/CameraDataAdapter.java @@ -276,6 +276,14 @@ public class CameraDataAdapter implements LocalDataAdapter { } private class QueryTask extends AsyncTask<ContentResolver, Void, List<LocalData>> { + + /** + * Loads all the photo and video data in the camera folder in background + * and combine them into one single list. + * + * @param resolver {@link ContentResolver} to load all the data. + * @return An {@link ArrayList} of all loaded data. + */ @Override protected List<LocalData> doInBackground(ContentResolver... resolver) { List<LocalData> l = new ArrayList<LocalData>(); diff --git a/src/com/android/camera/data/FixedFirstDataAdapter.java b/src/com/android/camera/data/FixedFirstDataAdapter.java index ecb9c1402..9f3c4107b 100644 --- a/src/com/android/camera/data/FixedFirstDataAdapter.java +++ b/src/com/android/camera/data/FixedFirstDataAdapter.java @@ -20,7 +20,6 @@ import android.content.Context; import android.net.Uri; import android.view.View; -import com.android.camera.ui.FilmStripView; import com.android.camera.ui.FilmStripView.DataAdapter; import com.android.camera.ui.FilmStripView.ImageData; @@ -32,6 +31,9 @@ import com.android.camera.ui.FilmStripView.ImageData; public class FixedFirstDataAdapter extends AbstractLocalDataAdapterWrapper implements DataAdapter.Listener { + @SuppressWarnings("unused") + private static final String TAG = "CAM_FixedFirstDataAdapter"; + private LocalData mFirstData; private Listener mListener; diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index 5eceaa4f1..d99a4fcf5 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -516,6 +516,7 @@ public class FilmStripView extends ViewGroup { public void onDraw(Canvas c) { if (mViewInfo[mCurrentInfo] != null && mController.hasNewGeometry()) { layoutChildren(); + super.onDraw(c); } } |