Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2013 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 
     17 package com.android.camera.ui;
     18 
     19 import android.animation.ValueAnimator;
     20 import android.content.Context;
     21 import android.content.res.Resources;
     22 import android.graphics.Canvas;
     23 import android.graphics.Paint;
     24 import android.graphics.Rect;
     25 import android.graphics.drawable.Drawable;
     26 import android.util.AttributeSet;
     27 import android.view.View;
     28 
     29 import com.android.camera.FocusOverlayManager;
     30 import com.android.camera.debug.DebugPropertyHelper;
     31 import com.android.camera.debug.Log;
     32 import com.android.camera2.R;
     33 
     34 /**
     35  * Displays a focus indicator.
     36  */
     37 public class FocusOverlay extends View implements FocusOverlayManager.FocusUI {
     38     private static final Log.Tag TAG = new Log.Tag("FocusOverlay");
     39 
     40     /** System Properties switch to enable debugging focus UI. */
     41     private static final boolean CAPTURE_DEBUG_UI = DebugPropertyHelper.showCaptureDebugUI();
     42 
     43     private final static int FOCUS_DURATION_MS = 500;
     44     private final static int FOCUS_INDICATOR_ROTATION_DEGREES = 50;
     45 
     46     private final Drawable mFocusIndicator;
     47     private Drawable mFocusOuterRing;
     48     private final Rect mBounds = new Rect();
     49     private final ValueAnimator mFocusAnimation = new ValueAnimator();
     50 
     51     private Paint mDebugSolidPaint;
     52     private Paint mDebugCornersPaint;
     53     private Paint mDebugTextPaint;
     54     private int mDebugStartColor;
     55     private int mDebugSuccessColor;
     56     private int mDebugFailColor;
     57     private Rect mFocusDebugSolidRect;
     58     private Rect mFocusDebugCornersRect;
     59     private boolean mIsPassiveScan;
     60     private String mDebugMessage;
     61 
     62     private int mPositionX;
     63     private int mPositionY;
     64     private int mAngle;
     65     private final int mFocusIndicatorSize;
     66     private boolean mShowIndicator;
     67     private final int mFocusOuterRingSize;
     68 
     69     public FocusOverlay(Context context, AttributeSet attrs) {
     70         super(context, attrs);
     71         mFocusIndicator = getResources().getDrawable(R.drawable.focus_ring_touch_inner);
     72         mFocusIndicatorSize = getResources().getDimensionPixelSize(R.dimen.focus_inner_ring_size);
     73         mFocusOuterRing = getResources().getDrawable(R.drawable.focus_ring_touch_outer);
     74         mFocusOuterRingSize = getResources().getDimensionPixelSize(R.dimen.focus_outer_ring_size);
     75 
     76         if (CAPTURE_DEBUG_UI) {
     77             Resources res = getResources();
     78             mDebugStartColor = res.getColor(R.color.focus_debug);
     79             mDebugSuccessColor = res.getColor(R.color.focus_debug_success);
     80             mDebugFailColor = res.getColor(R.color.focus_debug_fail);
     81             mDebugTextPaint= new Paint();
     82             mDebugTextPaint.setColor(res.getColor(R.color.focus_debug_text));
     83             mDebugTextPaint.setStyle(Paint.Style.FILL);
     84             mDebugSolidPaint = new Paint();
     85             mDebugSolidPaint.setColor(res.getColor(R.color.focus_debug));
     86             mDebugSolidPaint.setAntiAlias(true);
     87             mDebugSolidPaint.setStyle(Paint.Style.STROKE);
     88             mDebugSolidPaint.setStrokeWidth(res.getDimension(R.dimen.focus_debug_stroke));
     89             mDebugCornersPaint = new Paint(mDebugSolidPaint);
     90             mDebugCornersPaint.setColor(res.getColor(R.color.focus_debug));
     91             mFocusDebugSolidRect = new Rect();
     92             mFocusDebugCornersRect = new Rect();
     93         }
     94     }
     95 
     96     @Override
     97     public boolean hasFaces() {
     98         // TODO: Add face detection support.
     99         return false;
    100     }
    101 
    102     @Override
    103     public void clearFocus() {
    104         mShowIndicator = false;
    105         if (CAPTURE_DEBUG_UI) {
    106             setVisibility(INVISIBLE);
    107         }
    108     }
    109 
    110     @Override
    111     public void setFocusPosition(int x, int y, boolean isPassiveScan) {
    112         setFocusPosition(x, y, isPassiveScan, 0, 0);
    113     }
    114 
    115     @Override
    116     public void setFocusPosition(int x, int y, boolean isPassiveScan, int aFsize, int aEsize) {
    117         mIsPassiveScan = isPassiveScan;
    118         mPositionX = x;
    119         mPositionY = y;
    120         mBounds.set(x - mFocusIndicatorSize / 2, y - mFocusIndicatorSize / 2,
    121                 x + mFocusIndicatorSize / 2, y + mFocusIndicatorSize / 2);
    122         mFocusIndicator.setBounds(mBounds);
    123         mFocusOuterRing.setBounds(x - mFocusOuterRingSize / 2, y - mFocusOuterRingSize / 2,
    124                 x + mFocusOuterRingSize / 2, y + mFocusOuterRingSize / 2);
    125 
    126         if (CAPTURE_DEBUG_UI) {
    127             mFocusOuterRing.setBounds(0, 0, 0, 0);
    128             if (isPassiveScan) {
    129                 // Use AE rect only.
    130                 mFocusDebugSolidRect.setEmpty();
    131                 int avg = (aFsize + aEsize) / 2;
    132                 mFocusDebugCornersRect.set(x - avg / 2, y - avg / 2, x + avg / 2, y + avg / 2);
    133             } else {
    134                 mFocusDebugSolidRect.set(x - aFsize / 2, y - aFsize / 2, x + aFsize / 2,
    135                         y + aFsize / 2);
    136                 // If AE region is different size than AF region and active scan.
    137                 if (aFsize != aEsize) {
    138                     mFocusDebugCornersRect.set(x - aEsize / 2, y - aEsize / 2, x + aEsize / 2,
    139                             y + aEsize / 2);
    140                 } else {
    141                     mFocusDebugCornersRect.setEmpty();
    142                 }
    143             }
    144             mDebugSolidPaint.setColor(mDebugStartColor);
    145             mDebugCornersPaint.setColor(mDebugStartColor);
    146         }
    147 
    148         if (getVisibility() != VISIBLE) {
    149             setVisibility(VISIBLE);
    150         }
    151         invalidate();
    152     }
    153 
    154     /**
    155      * This is called in:
    156      * <ul>
    157      * <li>API1 non-CAF after autoFocus().</li>
    158      * <li>API1 CAF mode for onAutoFocusMoving(true).</li>
    159      * <li>API2 for transition to ACTIVE_SCANNING or PASSIVE_SCANNING.</li>
    160      * <ul>
    161      * TODO after PhotoModule/GcamModule deprecation: Do not use this for CAF.
    162      */
    163     @Override
    164     public void onFocusStarted() {
    165         mShowIndicator = true;
    166         mFocusAnimation.setIntValues(0, FOCUS_INDICATOR_ROTATION_DEGREES);
    167         mFocusAnimation.setDuration(FOCUS_DURATION_MS);
    168         mFocusAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    169             @Override
    170             public void onAnimationUpdate(ValueAnimator animation) {
    171                 mAngle = (Integer) animation.getAnimatedValue();
    172                 invalidate();
    173             }
    174         });
    175         mFocusAnimation.start();
    176         if (CAPTURE_DEBUG_UI) {
    177             mDebugMessage = null;
    178         }
    179     }
    180 
    181     /**
    182      * This is called in:
    183      * <ul>
    184      * <li>API1 non-CAF for onAutoFocus(true).</li>
    185      * <li>API2 non-CAF for transition to FOCUSED_LOCKED.</li>
    186      * <li>API1 CAF mode for onAutoFocusMoving(false).</li>
    187      * <ul>
    188      * TODO after PhotoModule/GcamModule deprecation: Do not use this for CAF.
    189      */
    190     @Override
    191     public void onFocusSucceeded() {
    192         mFocusAnimation.cancel();
    193         mShowIndicator = false;
    194         if (CAPTURE_DEBUG_UI && !mIsPassiveScan) {
    195             mDebugSolidPaint.setColor(mDebugSuccessColor);
    196         }
    197         invalidate();
    198     }
    199 
    200     /**
    201      * This is called in:
    202      * <ul>
    203      * <li>API1 non-CAF for onAutoFocus(false).</li>
    204      * <li>API2 non-CAF for transition to NOT_FOCUSED_LOCKED.</li>
    205      * <ul>
    206      */
    207     @Override
    208     public void onFocusFailed() {
    209         mFocusAnimation.cancel();
    210         mShowIndicator = false;
    211         if (CAPTURE_DEBUG_UI && !mIsPassiveScan) {
    212             mDebugSolidPaint.setColor(mDebugFailColor);
    213         }
    214         invalidate();
    215     }
    216 
    217     /**
    218      * This is called in:
    219      * API2 for CAF state changes to PASSIVE_FOCUSED or PASSIVE_UNFOCUSED.
    220      */
    221     @Override
    222     public void setPassiveFocusSuccess(boolean success) {
    223         mFocusAnimation.cancel();
    224         mShowIndicator = false;
    225         if (CAPTURE_DEBUG_UI) {
    226             mDebugCornersPaint.setColor(success ? mDebugSuccessColor : mDebugFailColor);
    227         }
    228         invalidate();
    229     }
    230 
    231     @Override
    232     public void showDebugMessage(String message) {
    233         if (CAPTURE_DEBUG_UI) {
    234             mDebugMessage = message;
    235         }
    236     }
    237 
    238     @Override
    239     public void pauseFaceDetection() {
    240         // TODO: Add face detection support.
    241     }
    242 
    243     @Override
    244     public void resumeFaceDetection() {
    245         // TODO: Add face detection support.
    246     }
    247 
    248     @Override
    249     public void onDraw(Canvas canvas) {
    250         super.onDraw(canvas);
    251 
    252         if (mShowIndicator) {
    253             mFocusOuterRing.draw(canvas);
    254             canvas.save();
    255             canvas.rotate(mAngle, mPositionX, mPositionY);
    256             mFocusIndicator.draw(canvas);
    257             canvas.restore();
    258         }
    259         if (CAPTURE_DEBUG_UI) {
    260             canvas.drawRect(mFocusDebugSolidRect, mDebugSolidPaint);
    261             float delta = 0.1f * mFocusDebugCornersRect.width();
    262             float left = mFocusDebugCornersRect.left;
    263             float top = mFocusDebugCornersRect.top;
    264             float right = mFocusDebugCornersRect.right;
    265             float bot = mFocusDebugCornersRect.bottom;
    266 
    267             canvas.drawLines(new float[]{left, top + delta, left, top, left, top, left + delta, top}, mDebugCornersPaint);
    268             canvas.drawLines(new float[]{right, top + delta, right, top, right, top, right - delta, top}, mDebugCornersPaint);
    269             canvas.drawLines(new float[]{left, bot - delta, left, bot, left, bot, left + delta, bot}, mDebugCornersPaint);
    270             canvas.drawLines(new float[]{right, bot - delta, right, bot, right, bot, right - delta, bot}, mDebugCornersPaint);
    271 
    272             if (mDebugMessage != null) {
    273                 mDebugTextPaint.setTextSize(40);
    274                 canvas.drawText(mDebugMessage, left - 4, bot + 44, mDebugTextPaint);
    275             }
    276         }
    277     }
    278 }
    279