summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CaptureModule.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CaptureModule.java')
-rw-r--r--src/com/android/camera/CaptureModule.java156
1 files changed, 144 insertions, 12 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 0ade6b164..71eba6859 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -47,6 +47,8 @@ import com.android.camera.debug.Log.Tag;
import com.android.camera.hardware.HardwareSpec;
import com.android.camera.module.ModuleController;
import com.android.camera.one.OneCamera;
+import com.android.camera.one.OneCamera.AutoFocusMode;
+import com.android.camera.one.OneCamera.AutoFocusState;
import com.android.camera.one.OneCamera.CaptureReadyCallback;
import com.android.camera.one.OneCamera.Facing;
import com.android.camera.one.OneCamera.OpenCallback;
@@ -62,6 +64,8 @@ import com.android.camera.ui.PreviewStatusListener;
import com.android.camera.ui.TouchCoordinate;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.Size;
+import com.android.camera.util.SystemProperties;
+import com.android.camera.util.UsageStatistics;
import com.android.camera2.R;
import com.android.ex.camera2.portability.CameraAgent.CameraProxy;
@@ -87,6 +91,7 @@ public class CaptureModule extends CameraModule
implements MediaSaver.QueueListener,
ModuleController,
OneCamera.PictureCallback,
+ OneCamera.FocusStateListener,
PreviewStatusListener.PreviewAreaChangedListener,
RemoteCameraModule,
SensorEventListener,
@@ -140,6 +145,29 @@ public class CaptureModule extends CameraModule
}
};
+ /**
+ * Show AF target in center of preview and start animation.
+ */
+ Runnable mShowAutoFocusTargetInCenterRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mUI.setAutoFocusTarget(((int) (mPreviewArea.left + mPreviewArea.right)) / 2,
+ ((int) (mPreviewArea.top + mPreviewArea.bottom)) / 2);
+ mUI.showAutoFocusInProgress();
+ }
+ };
+
+ /**
+ * Hide AF target UI element.
+ */
+ Runnable mHideAutoFocusTargetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // showAutoFocusSuccess() just hides the AF UI.
+ mUI.showAutoFocusSuccess();
+ }
+ };
+
private static final Tag TAG = new Tag("CaptureModule");
private static final String PHOTO_MODULE_STRING_ID = "PhotoModule";
/** Enable additional debug output. */
@@ -152,6 +180,12 @@ public class CaptureModule extends CameraModule
*/
private static final int ON_RESUME_TASKS_DELAY_MSEC = 20;
+ /** System Properties switch to enable debugging focus UI. */
+ private static final String PROP_FOCUS_DEBUG_UI_KEY = "persist.camera.focus_debug_ui";
+ private static final String PROP_FOCUS_DEBUG_UI_OFF = "0";
+ private static final boolean FOCUS_DEBUG_UI = !PROP_FOCUS_DEBUG_UI_OFF
+ .equals(SystemProperties.get(PROP_FOCUS_DEBUG_UI_KEY, PROP_FOCUS_DEBUG_UI_OFF));
+
private final Object mDimensionLock = new Object();
/**
* Lock for race conditions in the SurfaceTextureListener callbacks.
@@ -186,6 +220,16 @@ public class CaptureModule extends CameraModule
private ModuleState mState = ModuleState.IDLE;
/** Current orientation of the device. */
private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
+ /** Current zoom value. */
+ private float mZoomValue = 1f;
+
+ /** True if in AF tap-to-focus sequence. */
+ private boolean mTapToFocusInProgress = false;
+
+ /** Persistence of Tap to Focus target UI after scan complete. */
+ private static final int FOCUS_HOLD_UI_MILLIS = 500;
+ /** Persistence of Tap to Focus target UI timeout. */
+ private static final int FOCUS_HOLD_UI_TIMEOUT_MILLIS = 1500;
/** Accelerometer data. */
private final float[] mGData = new float[3];
@@ -214,19 +258,16 @@ public class CaptureModule extends CameraModule
/** Current display rotation in degrees. */
private int mDisplayRotation;
- /** Current width of the screen, in pixels. */
+ /** Current screen width in pixels. */
private int mScreenWidth;
- /** Current height of the screen, in pixels. */
+ /** Current screen height in pixels. */
private int mScreenHeight;
- /** Current preview width, in pixels. */
+ /** Current width of preview frames from camera. */
private int mPreviewBufferWidth;
- /** Current preview height, in pixels. */
+ /** Current height of preview frames from camera.. */
private int mPreviewBufferHeight;
-
- // /** Current preview area width. */
- // private float mFullPreviewWidth;
- // /** Current preview area height. */
- // private float mFullPreviewHeight;
+ /** Area used by preview. */
+ RectF mPreviewArea;
/** The current preview transformation matrix. */
private Matrix mPreviewTranformationMatrix = new Matrix();
@@ -325,6 +366,7 @@ public class CaptureModule extends CameraModule
@Override
public void onPreviewAreaChanged(RectF previewArea) {
+ mPreviewArea = previewArea;
// mUI.updatePreviewAreaRect(previewArea);
// mUI.positionProgressOverlay(previewArea);
}
@@ -421,6 +463,7 @@ public class CaptureModule extends CameraModule
public void onReadyForCapture() {
Log.d(TAG, "Ready for capture.");
onPreviewStarted();
+ mCamera.setFocusStateListener(CaptureModule.this);
}
});
}
@@ -578,8 +621,97 @@ public class CaptureModule extends CameraModule
return false;
}
+ /**
+ * Focus sequence starts for zone around tap location for single tap.
+ */
@Override
public void onSingleTapUp(View view, int x, int y) {
+ Log.v(TAG, "onSingleTapUp x=" + x + " y=" + y);
+ // TODO: This should query actual capability.
+ if (mCameraFacing == Facing.FRONT) {
+ return;
+ }
+ triggerFocusAtScreenCoord(x, y);
+ }
+
+ // TODO: Consider refactoring FocusOverlayManager.
+ // Currently AF state transitions are controlled in OneCameraImpl.
+ // PhotoModule uses FocusOverlayManager which uses API1/portability
+ // logic and coordinates.
+
+ private void triggerFocusAtScreenCoord(int x, int y) {
+ mTapToFocusInProgress = true;
+ // Show UI immediately even though scan has not started yet.
+ mUI.setAutoFocusTarget(x, y);
+ mUI.showAutoFocusInProgress();
+ mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable);
+ mMainHandler.postDelayed(mHideAutoFocusTargetRunnable, FOCUS_HOLD_UI_TIMEOUT_MILLIS);
+
+ // Normalize coordinates to [0,1] per CameraOne API.
+ float points[] = new float[2];
+ points[0] = (x - mPreviewArea.left) / mPreviewArea.width();
+ points[1] = (y - mPreviewArea.top) / mPreviewArea.height();
+
+ // Rotate coordinates to portrait orientation per CameraOne API.
+ Matrix rotationMatrix = new Matrix();
+ rotationMatrix.setRotate(mDisplayRotation, 0.5f, 0.5f);
+ rotationMatrix.mapPoints(points);
+ mCamera.triggerFocusAndMeterAtPoint(points[0], points[1]);
+
+ // Log touch (screen coordinates).
+ if (mZoomValue == 1f) {
+ TouchCoordinate touchCoordinate = new TouchCoordinate(x - mPreviewArea.left,
+ y - mPreviewArea.top, mPreviewArea.width(), mPreviewArea.height());
+ // TODO: Add to logging: duration, rotation.
+ UsageStatistics.instance().tapToFocus(touchCoordinate, null);
+ }
+ }
+
+ /**
+ * This AF status listener does two things:
+ * <ol>
+ * <li>Ends tap-to-focus period when mode goes from AUTO to CONTINUOUS_PICTURE.</li>
+ * <li>Updates AF UI if tap-to-focus is not in progress.</li>
+ * </ol>
+ */
+ public void onFocusStatusUpdate(final AutoFocusMode mode, final AutoFocusState state) {
+ Log.v(TAG, "AF status is mode:" + mode + " state:" + state);
+
+ if (FOCUS_DEBUG_UI) {
+ // TODO: Add debug circle radius+color UI to FocusOverlay.
+ // mMainHandler.post(...)
+ }
+
+ // After tap to focus SCAN completes, clear UI after FOCUS_HOLD_UI_MILLIS.
+ if (mTapToFocusInProgress && mode == AutoFocusMode.AUTO &&
+ (state == AutoFocusState.STOPPED_FOCUSED ||
+ state == AutoFocusState.STOPPED_UNFOCUSED)) {
+ mMainHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mTapToFocusInProgress = false;
+ mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable);
+ mMainHandler.post(mHideAutoFocusTargetRunnable);
+ }
+ }, FOCUS_HOLD_UI_MILLIS);
+ }
+
+ // Use the OneCamera auto focus callbacks to show the UI, except for
+ // tap to focus where we show UI right away at touch, and then turn
+ // it off early at 0.5 sec, before the focus lock expires at 3 sec.
+ if (!mTapToFocusInProgress) {
+ switch (state) {
+ case SCANNING:
+ mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable);
+ mMainHandler.post(mShowAutoFocusTargetInCenterRunnable);
+ break;
+ case STOPPED_FOCUSED:
+ case STOPPED_UNFOCUSED:
+ mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable);
+ mMainHandler.post(mHideAutoFocusTargetRunnable);
+ break;
+ }
+ }
}
@Override
@@ -654,6 +786,7 @@ public class CaptureModule extends CameraModule
/***
* Update the preview transform based on the new dimensions.
+ * TODO: Make work with all: aspect ratios/resolutions x screens/cameras.
*/
private void updatePreviewTransform(int incomingWidth, int incomingHeight,
boolean forceUpdate) {
@@ -759,11 +892,9 @@ public class CaptureModule extends CameraModule
}
mPreviewTranformationMatrix.postScale(scale, scale, centerX, centerY);
+ // TODO: Take these quantities from mPreviewArea.
float previewWidth = effectiveWidth * scale;
float previewHeight = effectiveHeight * scale;
- // mFullPreviewWidth = previewWidth;
- // mFullPreviewHeight = previewHeight;
-
float previewCenterX = previewWidth / 2;
float previewCenterY = previewHeight / 2;
mPreviewTranformationMatrix.postTranslate(previewCenterX - centerX, previewCenterY
@@ -833,6 +964,7 @@ public class CaptureModule extends CameraModule
private void closeCamera() {
if (mCamera != null) {
+ mCamera.setFocusStateListener(null);
mCamera.close(null);
mCamera = null;
}