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