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