Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2009 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;
     18 
     19 import android.content.Context;
     20 import android.graphics.Canvas;
     21 import android.graphics.drawable.Drawable;
     22 import android.util.AttributeSet;
     23 import android.util.Log;
     24 import android.view.MotionEvent;
     25 import android.view.View;
     26 import android.view.animation.AnimationUtils;
     27 import android.widget.ImageView;
     28 
     29 /**
     30  * A widget which switchs between the {@code Camera} and the {@code VideoCamera}
     31  * activities.
     32  */
     33 public class Switcher extends ImageView implements View.OnTouchListener {
     34 
     35     @SuppressWarnings("unused")
     36     private static final String TAG = "Switcher";
     37 
     38     /** A callback to be called when the user wants to switch activity. */
     39     public interface OnSwitchListener {
     40         // Returns true if the listener agrees that the switch can be changed.
     41         public boolean onSwitchChanged(Switcher source, boolean onOff);
     42     }
     43 
     44     private static final int ANIMATION_SPEED = 200;
     45     private static final long NO_ANIMATION = -1;
     46 
     47     private boolean mSwitch = false;
     48     private int mPosition = 0;
     49     private long mAnimationStartTime = NO_ANIMATION;
     50     private int mAnimationStartPosition;
     51     private OnSwitchListener mListener;
     52 
     53     public Switcher(Context context, AttributeSet attrs) {
     54         super(context, attrs);
     55     }
     56 
     57     public void setSwitch(boolean onOff) {
     58         if (mSwitch == onOff) return;
     59         mSwitch = onOff;
     60         invalidate();
     61     }
     62 
     63     // Try to change the switch position. (The client can veto it.)
     64     private void tryToSetSwitch(boolean onOff) {
     65         try {
     66             if (mSwitch == onOff) return;
     67 
     68             if (mListener != null) {
     69                 if (!mListener.onSwitchChanged(this, onOff)) {
     70                     return;
     71                 }
     72             }
     73 
     74             mSwitch = onOff;
     75         } finally {
     76             startParkingAnimation();
     77         }
     78     }
     79 
     80     public void setOnSwitchListener(OnSwitchListener listener) {
     81         mListener = listener;
     82     }
     83 
     84     @Override
     85     public boolean onTouchEvent(MotionEvent event) {
     86         if (!isEnabled()) return false;
     87 
     88         final int available = getHeight() - getPaddingTop() - getPaddingBottom()
     89                 - getDrawable().getIntrinsicHeight();
     90 
     91         switch (event.getAction()) {
     92             case MotionEvent.ACTION_DOWN:
     93                 mAnimationStartTime = NO_ANIMATION;
     94                 setPressed(true);
     95                 trackTouchEvent(event);
     96                 break;
     97 
     98             case MotionEvent.ACTION_MOVE:
     99                 trackTouchEvent(event);
    100                 break;
    101 
    102             case MotionEvent.ACTION_UP:
    103                 trackTouchEvent(event);
    104                 tryToSetSwitch(mPosition >= available / 2);
    105                 setPressed(false);
    106                 break;
    107 
    108             case MotionEvent.ACTION_CANCEL:
    109                 tryToSetSwitch(mSwitch);
    110                 setPressed(false);
    111                 break;
    112         }
    113         return true;
    114     }
    115 
    116     private void startParkingAnimation() {
    117         mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis();
    118         mAnimationStartPosition = mPosition;
    119     }
    120 
    121     private void trackTouchEvent(MotionEvent event) {
    122         Drawable drawable = getDrawable();
    123         int drawableHeight = drawable.getIntrinsicHeight();
    124         final int height = getHeight();
    125         final int available = height - getPaddingTop() - getPaddingBottom()
    126                 - drawableHeight;
    127         int x = (int) event.getY();
    128         mPosition = x - getPaddingTop() - drawableHeight / 2;
    129         if (mPosition < 0) mPosition = 0;
    130         if (mPosition > available) mPosition = available;
    131         invalidate();
    132     }
    133 
    134     @Override
    135     protected void onDraw(Canvas canvas) {
    136 
    137         Drawable drawable = getDrawable();
    138         int drawableHeight = drawable.getIntrinsicHeight();
    139         int drawableWidth = drawable.getIntrinsicWidth();
    140 
    141         if (drawableWidth == 0 || drawableHeight == 0) {
    142             return;     // nothing to draw (empty bounds)
    143         }
    144 
    145         final int available = getHeight() - getPaddingTop()
    146                 - getPaddingBottom() - drawableHeight;
    147         if (mAnimationStartTime != NO_ANIMATION) {
    148             long time = AnimationUtils.currentAnimationTimeMillis();
    149             int deltaTime = (int) (time - mAnimationStartTime);
    150             mPosition = mAnimationStartPosition +
    151                     ANIMATION_SPEED * (mSwitch ? deltaTime : -deltaTime) / 1000;
    152             if (mPosition < 0) mPosition = 0;
    153             if (mPosition > available) mPosition = available;
    154             boolean done = (mPosition == (mSwitch ? available : 0));
    155             if (!done) {
    156                 invalidate();
    157             } else {
    158                 mAnimationStartTime = NO_ANIMATION;
    159             }
    160         } else if (!isPressed()){
    161             mPosition = mSwitch ? available : 0;
    162         }
    163         int offsetTop = getPaddingTop() + mPosition;
    164         int offsetLeft = (getWidth()
    165                 - drawableWidth - getPaddingLeft() - getPaddingRight()) / 2;
    166         int saveCount = canvas.getSaveCount();
    167         canvas.save();
    168         canvas.translate(offsetLeft, offsetTop);
    169         drawable.draw(canvas);
    170         canvas.restoreToCount(saveCount);
    171     }
    172 
    173     // Consume the touch events for the specified view.
    174     public void addTouchView(View v) {
    175         v.setOnTouchListener(this);
    176     }
    177 
    178     // This implements View.OnTouchListener so we intercept the touch events
    179     // and pass them to ourselves.
    180     public boolean onTouch(View v, MotionEvent event) {
    181         onTouchEvent(event);
    182         return true;
    183     }
    184 }
    185