diff options
author | Wu-cheng Li <wuchengli@google.com> | 2011-08-03 16:58:46 +0800 |
---|---|---|
committer | Wu-cheng Li <wuchengli@google.com> | 2011-08-04 17:59:20 +0800 |
commit | 4b602592e0d189499b22d107d997b83e798b5bd9 (patch) | |
tree | 4c711877033b204a6245f48a54e55238c49bbd9b | |
parent | bed7386688cd7810cba23732ab71f370fe3222ff (diff) | |
download | LegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.zip LegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.tar.gz LegacyCamera-4b602592e0d189499b22d107d997b83e798b5bd9.tar.bz2 |
Add face detection UI.
bug:4460717
Change-Id: Id09cc012efffcee0f5af3a070b5dcb775a7048a0
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | res/layout/face.xml | 25 | ||||
-rw-r--r-- | src/com/android/camera/Camera.java | 46 | ||||
-rw-r--r-- | src/com/android/camera/FaceListener.java | 131 | ||||
-rw-r--r-- | src/com/android/camera/Util.java | 7 | ||||
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 3 | ||||
-rw-r--r-- | src/com/android/camera/panorama/PanoramaActivity.java | 5 |
7 files changed, 199 insertions, 20 deletions
@@ -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); |