summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWu-cheng Li <wuchengli@google.com>2011-08-03 16:58:46 +0800
committerWu-cheng Li <wuchengli@google.com>2011-08-04 17:59:20 +0800
commit4b602592e0d189499b22d107d997b83e798b5bd9 (patch)
tree4c711877033b204a6245f48a54e55238c49bbd9b
parentbed7386688cd7810cba23732ab71f370fe3222ff (diff)
downloadLegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.zip
LegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.tar.gz
LegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.tar.bz2
Add face detection UI.
bug:4460717 Change-Id: Id09cc012efffcee0f5af3a070b5dcb775a7048a0
-rw-r--r--Android.mk2
-rw-r--r--res/layout/face.xml25
-rw-r--r--src/com/android/camera/Camera.java46
-rw-r--r--src/com/android/camera/FaceListener.java131
-rw-r--r--src/com/android/camera/Util.java7
-rw-r--r--src/com/android/camera/VideoCamera.java3
-rw-r--r--src/com/android/camera/panorama/PanoramaActivity.java5
7 files changed, 199 insertions, 20 deletions
diff --git a/Android.mk b/Android.mk
index 43db977..616047c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,7 +6,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Camera
-LOCAL_SDK_VERSION := current
+#LOCAL_SDK_VERSION := current
LOCAL_JNI_SHARED_LIBRARIES := libjni_mosaic
diff --git a/res/layout/face.xml b/res/layout/face.xml
new file mode 100644
index 0000000..a4eb468
--- /dev/null
+++ b/res/layout/face.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011 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.
+*/
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="@drawable/focus_focused"
+ android:visibility="gone" />
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index a89c676..151eecb 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -17,11 +17,9 @@
package com.android.camera;
import com.android.camera.ui.FocusRectangle;
-import com.android.camera.ui.GLRootView;
import com.android.camera.ui.IndicatorControl;
import com.android.camera.ui.RotateImageView;
import com.android.camera.ui.SharePopup;
-import com.android.camera.ui.ZoomControllerListener;
import com.android.camera.ui.ZoomPicker;
import android.app.Activity;
@@ -32,7 +30,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences.Editor;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.hardware.Camera.Area;
@@ -159,8 +156,6 @@ public class Camera extends ActivityBase implements View.OnClickListener,
private List<Area> mFocusArea; // focus area in driver format
private static final int RESET_TOUCH_FOCUS_DELAY = 3000;
- private GLRootView mGLRootView;
-
// A popup window that contains a bigger thumbnail and a list of apps to share.
private SharePopup mSharePopup;
// The bitmap of the last captured picture thumbnail and the URI of the
@@ -193,6 +188,8 @@ public class Camera extends ActivityBase implements View.OnClickListener,
// The display rotation in degrees. This is only valid when mCameraState is
// not PREVIEW_STOPPED.
private int mDisplayRotation;
+ // The value for android.hardware.Camera.setDisplayOrientation.
+ private int mDisplayOrientation;
private boolean mPausing;
private boolean mFirstTimeInitialized;
private boolean mIsImageCaptureIntent;
@@ -222,6 +219,7 @@ public class Camera extends ActivityBase implements View.OnClickListener,
private final AutoFocusCallback mAutoFocusCallback =
new AutoFocusCallback();
private final ZoomListener mZoomListener = new ZoomListener();
+ private FaceListener mFaceListener;
private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
private long mFocusStartTime;
@@ -314,6 +312,7 @@ public class Camera extends ActivityBase implements View.OnClickListener,
case RESET_TOUCH_FOCUS: {
cancelAutoFocus();
+ startFaceDetection();
break;
}
}
@@ -390,6 +389,7 @@ public class Camera extends ActivityBase implements View.OnClickListener,
installIntentFilter();
initializeFocusTone();
initializeZoom();
+ startFaceDetection();
mFirstTimeInitialized = true;
addIdleHandler();
}
@@ -439,7 +439,7 @@ public class Camera extends ActivityBase implements View.OnClickListener,
installIntentFilter();
initializeFocusTone();
initializeZoom();
-
+ startFaceDetection();
keepMediaProviderInstance();
checkStorage();
@@ -512,6 +512,26 @@ public class Camera extends ActivityBase implements View.OnClickListener,
}
}
+ private void startFaceDetection() {
+ if (mParameters.getMaxNumDetectedFaces(
+ android.hardware.Camera.CAMERA_FACE_DETECTION_HW) > 0) {
+ if (mFaceListener == null) {
+ mFaceListener = new FaceListener(this,
+ (ViewGroup) findViewById(R.id.frame), mDisplayOrientation);
+ }
+ mCameraDevice.setFaceDetectionListener(mFaceListener);
+ mCameraDevice.startFaceDetection(android.hardware.Camera.CAMERA_FACE_DETECTION_HW);
+ }
+ }
+
+ private void stopFaceDetection() {
+ if (mParameters.getMaxNumDetectedFaces(
+ android.hardware.Camera.CAMERA_FACE_DETECTION_HW) > 0) {
+ mCameraDevice.setFaceDetectionListener(null);
+ mCameraDevice.stopFaceDetection();
+ }
+ }
+
private class PopupGestureListener
extends GestureDetector.SimpleOnGestureListener {
@Override
@@ -1557,10 +1577,6 @@ public class Camera extends ActivityBase implements View.OnClickListener,
int areaHeight = focusHeight * 2;
int areaLeft = Util.clamp(x - areaWidth / 2, 0, previewWidth - areaWidth);
int areaTop = Util.clamp(y - areaHeight / 2, 0, previewHeight - areaHeight);
- Log.d(TAG, "x=" + x + ". y=" + y);
- Log.d(TAG, "Focus area left=" + areaLeft + ". top=" + areaTop);
- Log.d(TAG, "Preview width=" + previewWidth + ". height=" + previewHeight);
- Log.d(TAG, "focusWidth=" + focusWidth + ". focusHeight=" + focusHeight);
Rect rect = mFocusArea.get(0).rect;
convertToFocusArea(areaLeft, areaTop, areaWidth, areaHeight, previewWidth, previewHeight,
mFocusArea.get(0).rect);
@@ -1576,6 +1592,9 @@ public class Camera extends ActivityBase implements View.OnClickListener,
rules[RelativeLayout.CENTER_IN_PARENT] = 0;
mFocusRectangle.requestLayout();
+ // Stop face detection because we want to specify focus and metering area.
+ stopFaceDetection();
+
// Set the focus area and metering area.
setCameraParameters(UPDATE_PARAM_PREFERENCE);
if (callAutoFocusRequired && e.getAction() == MotionEvent.ACTION_UP) {
@@ -1806,10 +1825,13 @@ public class Camera extends ActivityBase implements View.OnClickListener,
setPreviewDisplay(mSurfaceHolder);
mDisplayRotation = Util.getDisplayRotation(this);
- Util.setCameraDisplayOrientation(mDisplayRotation, mCameraId, mCameraDevice);
+ mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId);
+ mCameraDevice.setDisplayOrientation(mDisplayOrientation);
+ if (mFaceListener != null) {
+ mFaceListener.setDisplayOrientation(mDisplayOrientation);
+ }
setCameraParameters(UPDATE_PARAM_ALL);
-
try {
Log.v(TAG, "startPreview");
mCameraDevice.startPreview();
diff --git a/src/com/android/camera/FaceListener.java b/src/com/android/camera/FaceListener.java
new file mode 100644
index 0000000..5b90523
--- /dev/null
+++ b/src/com/android/camera/FaceListener.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.hardware.Camera.Face;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+class FaceListener implements android.hardware.Camera.FaceDetectionListener {
+ private final String TAG = "FaceListener";
+ private final boolean LOGV = true;
+ private final int MAX_NUM_FACES = 10; // Show 10 faces at most.
+ private final Context mContext;
+ private final ViewGroup mFrame;
+ private int mDisplayOrientation;
+ private View mFaces[] = new View[MAX_NUM_FACES];
+
+ public FaceListener(Context context, ViewGroup frame, int orientation) {
+ mContext = context;
+ mFrame = frame;
+ setDisplayOrientation(orientation);
+ }
+
+ @Override
+ public void onFaceDetection(Face[] faces, android.hardware.Camera camera) {
+ if (faces.length == 0) return;
+ if (LOGV) Log.v(TAG, "Num of faces=" + faces.length);
+
+ // Rotate the coordinates if necessary.
+ if (mDisplayOrientation != 0) rotateFaces(faces);
+ showFaces(faces);
+ }
+
+ public void setDisplayOrientation(int orientation) {
+ mDisplayOrientation = orientation;
+ if (LOGV) Log.v(TAG, "mDisplayOrientation=" + orientation);
+ }
+
+ private void rotateFaces(Face[] faces) {
+ int tmp;
+ for (Face face: faces) {
+ Rect rect = face.rect;
+ if (LOGV) dumpRect(rect, "Original rect");
+ if (mDisplayOrientation== 90) {
+ tmp = rect.left;
+ rect.left = rect.top; // x' = y
+ rect.top = -tmp; // y' = -x
+ tmp = rect.right;
+ rect.right = rect.bottom;
+ rect.bottom = -tmp;
+ } else if (mDisplayOrientation == 180) {
+ rect.left *= -1; // x' = -x
+ rect.top *= -1; // y' = -y
+ rect.right *= -1;
+ rect.bottom *= -1;
+ } else if (mDisplayOrientation == 270) {
+ tmp = rect.left;
+ rect.left = -rect.top; // x' = -y
+ rect.top = tmp; // y' = x
+ tmp = rect.right;
+ rect.right = -rect.bottom;
+ rect.bottom = tmp;
+ }
+ if (LOGV) dumpRect(rect, "Rotated rect");
+ }
+ }
+
+ private void showFaces(Face[] faces) {
+ // The range of the coordinates from the driver is -1000 to 1000.
+ // So the maximum length of the width or height is 2000. We need to
+ // convert them to UI layout size later.
+ double widthRatio = mFrame.getWidth() / 2000.0;
+ double heightRatio = mFrame.getHeight() / 2000.0;
+ for (int i = 0; i < MAX_NUM_FACES; i++) {
+ if (i < faces.length) {
+ // Inflate the view if it's not done yet.
+ if (mFaces[i] == null) {
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mFaces[i] = inflater.inflate(R.layout.face, null);
+ mFrame.addView(mFaces[i]);
+ }
+
+ // Set width and height.
+ Rect rect = faces[i].rect;
+ RelativeLayout.LayoutParams p =
+ (RelativeLayout.LayoutParams) mFaces[i].getLayoutParams();
+ p.width = (int) (rect.width() * widthRatio);
+ p.height = (int) (rect.height() * heightRatio);
+
+ // Set margins. Add 1000 so the range is 0 to 2000.
+ int left = (int) ((rect.left + 1000) * widthRatio);
+ int top = (int) ((rect.top + 1000) * heightRatio);
+ p.setMargins(left, top, 0, 0);
+ mFaces[i].setLayoutParams(p);
+ if (LOGV) {
+ Log.v(TAG, "Face w="+p.width+".h="+p.height+".margin left="+left+".top="+top);
+ }
+
+ mFaces[i].setVisibility(View.VISIBLE);
+ mFaces[i].requestLayout();
+ } else {
+ if (mFaces[i] != null) mFaces[i].setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void dumpRect(Rect rect, String msg) {
+ Log.v(TAG, msg + "=(" + rect.left + "," + rect.top
+ + "," + rect.right + "," + rect.bottom + ")");
+ }
+}
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index d3fa24e..2b39b3d 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -295,9 +295,8 @@ public class Util {
return 0;
}
- public static void setCameraDisplayOrientation(int degrees,
- int cameraId, Camera camera) {
- // See android.hardware.Camera.setCameraDisplayOrientation for
+ public static int getDisplayOrientation(int degrees, int cameraId) {
+ // See android.hardware.Camera.setDisplayOrientation for
// documentation.
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
@@ -308,7 +307,7 @@ public class Util {
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
- camera.setDisplayOrientation(result);
+ return result;
}
public static Size getOptimalPreviewSize(Activity currentActivity,
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 54871f2..bcbb68b 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -855,7 +855,8 @@ public class VideoCamera extends ActivityBase
}
setPreviewDisplay(mSurfaceHolder);
mDisplayRotation = Util.getDisplayRotation(this);
- Util.setCameraDisplayOrientation(mDisplayRotation, mCameraId, mCameraDevice);
+ int orientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId);
+ mCameraDevice.setDisplayOrientation(orientation);
setCameraParameters();
try {
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index 770ba51..bf4949c 100644
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -196,8 +196,9 @@ public class PanoramaActivity extends Activity implements ModePicker.OnModeChang
private void configureCamera(Parameters parameters) {
mCameraDevice.setParameters(parameters);
- Util.setCameraDisplayOrientation(Util.getDisplayRotation(this), CameraHolder.instance()
- .getBackCameraId(), mCameraDevice);
+ int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this),
+ CameraHolder.instance().getBackCameraId());
+ mCameraDevice.setDisplayOrientation(orientation);
int bufSize = getPreviewBufSize();
Log.v(TAG, "BufSize = " + bufSize);