141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li/* 241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * Copyright (C) 2011 The Android Open Source Project 341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * 441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * Licensed under the Apache License, Version 2.0 (the "License"); 541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * you may not use this file except in compliance with the License. 641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * You may obtain a copy of the License at 741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * 841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * http://www.apache.org/licenses/LICENSE-2.0 941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * 1041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * Unless required by applicable law or agreed to in writing, software 1141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * distributed under the License is distributed on an "AS IS" BASIS, 1241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * See the License for the specific language governing permissions and 1441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li * limitations under the License. 1541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li */ 1641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 1741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Lipackage com.android.camera.ui; 1841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 1941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport com.android.camera.R; 2041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport com.android.camera.Util; 2141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 2241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.content.Context; 2341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.graphics.Canvas; 2441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.graphics.Matrix; 2541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.graphics.RectF; 2641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.graphics.drawable.Drawable; 2741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.hardware.Camera.Face; 2841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.util.AttributeSet; 2941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.util.Log; 3041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Liimport android.view.View; 3141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 323ebe49d8f1b4defb7cfd4850a14e795aada2ebd1Chih-yu Huangpublic class FaceView extends View implements FocusIndicator, Rotatable { 3341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private final String TAG = "FaceView"; 3441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private final boolean LOGV = false; 35c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // The value for android.hardware.Camera.setDisplayOrientation. 3641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private int mDisplayOrientation; 37c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // The orientation compensation for the face indicator to make it look 38c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // correctly in all device orientations. Ex: if the value is 90, the 39c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // indicator should be rotated 90 degrees counter-clockwise. 40c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li private int mOrientation; 4141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private boolean mMirror; 42d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li private boolean mPause; 4341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private Matrix mMatrix = new Matrix(); 4441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private RectF mRect = new RectF(); 4541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li private Face[] mFaces; 4620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li private Drawable mFaceIndicator; 4720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li private final Drawable mDrawableFocusing; 4820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li private final Drawable mDrawableFocused; 4920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li private final Drawable mDrawableFocusFailed; 5041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 5141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li public FaceView(Context context, AttributeSet attrs) { 5241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li super(context, attrs); 5320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mDrawableFocusing = getResources().getDrawable(R.drawable.ic_focus_focusing); 5420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mDrawableFocused = getResources().getDrawable(R.drawable.ic_focus_face_focused); 5520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mDrawableFocusFailed = getResources().getDrawable(R.drawable.ic_focus_failed); 5620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator = mDrawableFocusing; 5741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 5841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 5941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li public void setFaces(Face[] faces) { 6041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li if (LOGV) Log.v(TAG, "Num of faces=" + faces.length); 61d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li if (mPause) return; 6241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mFaces = faces; 6341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li invalidate(); 6441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 6541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 6641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li public void setDisplayOrientation(int orientation) { 6741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mDisplayOrientation = orientation; 6841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li if (LOGV) Log.v(TAG, "mDisplayOrientation=" + orientation); 6941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 7041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 71c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li public void setOrientation(int orientation) { 72c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li mOrientation = orientation; 73c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li invalidate(); 74c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li } 75c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li 7641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li public void setMirror(boolean mirror) { 7741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mMirror = mirror; 7841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li if (LOGV) Log.v(TAG, "mMirror=" + mirror); 7941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 8041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 8141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li public boolean faceExists() { 8241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li return (mFaces != null && mFaces.length > 0); 8341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 8441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 8520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li @Override 8620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li public void showStart() { 8720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator = mDrawableFocusing; 8820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li invalidate(); 8920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li } 9020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li 9120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li @Override 9220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li public void showSuccess() { 9320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator = mDrawableFocused; 9420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li invalidate(); 9520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li } 9620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li 9720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li @Override 9820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li public void showFail() { 9920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator = mDrawableFocusFailed; 10020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li invalidate(); 10120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li } 10220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li 10320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li @Override 10420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li public void clear() { 10520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li // Face indicator is displayed during preview. Do not clear the 10620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li // drawable. 10720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator = mDrawableFocusing; 10841ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mFaces = null; 10941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li invalidate(); 11041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 11141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 112d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li public void pause() { 113d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li mPause = true; 114d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li } 115d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li 116d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li public void resume() { 117d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li mPause = false; 118d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li } 119d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li 12041ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li @Override 12141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li protected void onDraw(Canvas canvas) { 12241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li if (mFaces != null && mFaces.length > 0) { 12341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li // Prepare the matrix. 124048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang Util.prepareMatrix(mMatrix, mMirror, mDisplayOrientation, getWidth(), getHeight()); 12541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 126c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // Focus indicator is directional. Rotate the matrix and the canvas 127c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li // so it looks correctly in all orientations. 128c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li canvas.save(); 129c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li mMatrix.postRotate(mOrientation); // postRotate is clockwise 130c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li canvas.rotate(-mOrientation); // rotate is counter-clockwise (for canvas) 13141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li for (int i = 0; i < mFaces.length; i++) { 13241ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li // Transform the coordinates. 13341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mRect.set(mFaces[i].rect); 134048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang if (LOGV) Util.dumpRect(mRect, "Original rect"); 13541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li mMatrix.mapRect(mRect); 136048edf2ef22607b85bc4b062e2af71804f5b3530Chih-yu Huang if (LOGV) Util.dumpRect(mRect, "Transformed rect"); 13741ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li 13820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator.setBounds(Math.round(mRect.left), Math.round(mRect.top), 13941ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li Math.round(mRect.right), Math.round(mRect.bottom)); 14020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li mFaceIndicator.draw(canvas); 14141ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 142c7e69709baea0cd9e49eed005d85714326b27da1Wu-cheng Li canvas.restore(); 14341ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 14441ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li super.onDraw(canvas); 14541ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li } 14641ecefdc167ca88d785e6a1d58b706cc7f03c2bdWu-cheng Li} 147