blob: 8d5c292ca59a38bd334998bf52ca00855b4c7303 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera.ui;
18
Michael Kolb8872c232013-01-29 10:33:22 -080019import android.content.Context;
20import android.content.res.Resources;
21import android.graphics.Canvas;
22import android.graphics.Matrix;
23import android.graphics.Paint;
24import android.graphics.Paint.Style;
25import android.graphics.RectF;
26import android.hardware.Camera.Face;
27import android.os.Handler;
28import android.os.Message;
29import android.util.AttributeSet;
Michael Kolb8872c232013-01-29 10:33:22 -080030import android.view.View;
31
Angus Kong2bca2102014-03-11 16:27:30 -070032import com.android.camera.debug.Log;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070033import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070034import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -080035
Doris Liu753bb8a2013-03-14 21:01:35 -070036public class FaceView extends View
Angus Kong2bacca72014-03-06 12:57:29 -080037 implements FocusIndicator, Rotatable, PreviewStatusListener.PreviewAreaChangedListener {
Angus Kong2bca2102014-03-11 16:27:30 -070038 private static final Log.Tag TAG = new Log.Tag("FaceView");
Michael Kolb8872c232013-01-29 10:33:22 -080039 private final boolean LOGV = false;
40 // The value for android.hardware.Camera.setDisplayOrientation.
41 private int mDisplayOrientation;
42 // The orientation compensation for the face indicator to make it look
43 // correctly in all device orientations. Ex: if the value is 90, the
44 // indicator should be rotated 90 degrees counter-clockwise.
45 private int mOrientation;
46 private boolean mMirror;
47 private boolean mPause;
48 private Matrix mMatrix = new Matrix();
49 private RectF mRect = new RectF();
50 // As face detection can be flaky, we add a layer of filtering on top of it
51 // to avoid rapid changes in state (eg, flickering between has faces and
52 // not having faces)
53 private Face[] mFaces;
54 private Face[] mPendingFaces;
55 private int mColor;
56 private final int mFocusingColor;
57 private final int mFocusedColor;
58 private final int mFailColor;
59 private Paint mPaint;
60 private volatile boolean mBlocked;
61
62 private static final int MSG_SWITCH_FACES = 1;
63 private static final int SWITCH_DELAY = 70;
64 private boolean mStateSwitchPending = false;
65 private Handler mHandler = new Handler() {
66 @Override
67 public void handleMessage(Message msg) {
68 switch (msg.what) {
69 case MSG_SWITCH_FACES:
70 mStateSwitchPending = false;
71 mFaces = mPendingFaces;
72 invalidate();
73 break;
74 }
75 }
76 };
Doris Liu59401042014-01-14 17:51:32 -080077 private final RectF mPreviewArea = new RectF();
Michael Kolb8872c232013-01-29 10:33:22 -080078
79 public FaceView(Context context, AttributeSet attrs) {
80 super(context, attrs);
81 Resources res = getResources();
82 mFocusingColor = res.getColor(R.color.face_detect_start);
83 mFocusedColor = res.getColor(R.color.face_detect_success);
84 mFailColor = res.getColor(R.color.face_detect_fail);
85 mColor = mFocusingColor;
86 mPaint = new Paint();
87 mPaint.setAntiAlias(true);
88 mPaint.setStyle(Style.STROKE);
89 mPaint.setStrokeWidth(res.getDimension(R.dimen.face_circle_stroke));
90 }
91
92 public void setFaces(Face[] faces) {
Angus Kong2bca2102014-03-11 16:27:30 -070093 if (LOGV) {
94 Log.v(TAG, "Num of faces=" + faces.length);
95 }
Michael Kolb8872c232013-01-29 10:33:22 -080096 if (mPause) return;
97 if (mFaces != null) {
98 if ((faces.length > 0 && mFaces.length == 0)
99 || (faces.length == 0 && mFaces.length > 0)) {
100 mPendingFaces = faces;
101 if (!mStateSwitchPending) {
102 mStateSwitchPending = true;
103 mHandler.sendEmptyMessageDelayed(MSG_SWITCH_FACES, SWITCH_DELAY);
104 }
105 return;
106 }
107 }
108 if (mStateSwitchPending) {
109 mStateSwitchPending = false;
110 mHandler.removeMessages(MSG_SWITCH_FACES);
111 }
112 mFaces = faces;
113 invalidate();
114 }
115
116 public void setDisplayOrientation(int orientation) {
117 mDisplayOrientation = orientation;
Angus Kong2bca2102014-03-11 16:27:30 -0700118 if (LOGV) {
119 Log.v(TAG, "mDisplayOrientation=" + orientation);
120 }
Michael Kolb8872c232013-01-29 10:33:22 -0800121 }
122
123 @Override
124 public void setOrientation(int orientation, boolean animation) {
125 mOrientation = orientation;
126 invalidate();
127 }
128
129 public void setMirror(boolean mirror) {
130 mMirror = mirror;
Angus Kong2bca2102014-03-11 16:27:30 -0700131 if (LOGV) {
132 Log.v(TAG, "mMirror=" + mirror);
133 }
Michael Kolb8872c232013-01-29 10:33:22 -0800134 }
135
136 public boolean faceExists() {
137 return (mFaces != null && mFaces.length > 0);
138 }
139
140 @Override
141 public void showStart() {
142 mColor = mFocusingColor;
143 invalidate();
144 }
145
146 // Ignore the parameter. No autofocus animation for face detection.
147 @Override
148 public void showSuccess(boolean timeout) {
149 mColor = mFocusedColor;
150 invalidate();
151 }
152
153 // Ignore the parameter. No autofocus animation for face detection.
154 @Override
155 public void showFail(boolean timeout) {
156 mColor = mFailColor;
157 invalidate();
158 }
159
160 @Override
161 public void clear() {
162 // Face indicator is displayed during preview. Do not clear the
163 // drawable.
164 mColor = mFocusingColor;
165 mFaces = null;
166 invalidate();
167 }
168
169 public void pause() {
170 mPause = true;
171 }
172
173 public void resume() {
174 mPause = false;
175 }
176
177 public void setBlockDraw(boolean block) {
178 mBlocked = block;
179 }
180
181 @Override
182 protected void onDraw(Canvas canvas) {
183 if (!mBlocked && (mFaces != null) && (mFaces.length > 0)) {
Doris Liu753bb8a2013-03-14 21:01:35 -0700184 int rw, rh;
Doris Liu59401042014-01-14 17:51:32 -0800185 rw = (int) mPreviewArea.width();
186 rh = (int) mPreviewArea.height();
Michael Kolb8872c232013-01-29 10:33:22 -0800187 // Prepare the matrix.
188 if (((rh > rw) && ((mDisplayOrientation == 0) || (mDisplayOrientation == 180)))
189 || ((rw > rh) && ((mDisplayOrientation == 90) || (mDisplayOrientation == 270)))) {
190 int temp = rw;
191 rw = rh;
192 rh = temp;
193 }
Angus Kongb50b5cb2013-08-09 14:55:20 -0700194 CameraUtil.prepareMatrix(mMatrix, mMirror, mDisplayOrientation, rw, rh);
Michael Kolb8872c232013-01-29 10:33:22 -0800195 // Focus indicator is directional. Rotate the matrix and the canvas
196 // so it looks correctly in all orientations.
197 canvas.save();
198 mMatrix.postRotate(mOrientation); // postRotate is clockwise
199 canvas.rotate(-mOrientation); // rotate is counter-clockwise (for canvas)
200 for (int i = 0; i < mFaces.length; i++) {
201 // Filter out false positives.
202 if (mFaces[i].score < 50) continue;
203
204 // Transform the coordinates.
205 mRect.set(mFaces[i].rect);
Angus Kong2bca2102014-03-11 16:27:30 -0700206 if (LOGV) {
207 CameraUtil.dumpRect(mRect, "Original rect");
208 }
Michael Kolb8872c232013-01-29 10:33:22 -0800209 mMatrix.mapRect(mRect);
Angus Kong2bca2102014-03-11 16:27:30 -0700210 if (LOGV) {
211 CameraUtil.dumpRect(mRect, "Transformed rect");
212 }
Michael Kolb8872c232013-01-29 10:33:22 -0800213 mPaint.setColor(mColor);
Doris Liu59401042014-01-14 17:51:32 -0800214 mRect.offset(mPreviewArea.left, mPreviewArea.top);
Michael Kolb8872c232013-01-29 10:33:22 -0800215 canvas.drawOval(mRect, mPaint);
216 }
217 canvas.restore();
218 }
219 super.onDraw(canvas);
220 }
Doris Liu59401042014-01-14 17:51:32 -0800221
222 @Override
Angus Kong2bacca72014-03-06 12:57:29 -0800223 public void onPreviewAreaChanged(RectF previewArea) {
Doris Liu59401042014-01-14 17:51:32 -0800224 mPreviewArea.set(previewArea);
225 }
Michael Kolb8872c232013-01-29 10:33:22 -0800226}