1 /*
2  * Copyright (C) 2008 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.text.method.Touch;
21 import android.util.AttributeSet;
22 import android.view.MotionEvent;
23 import android.view.View;
24 import android.widget.ImageView;
25 
26 import com.android.camera.debug.Log;
27 import com.android.camera.ui.TouchCoordinate;
28 
29 import java.util.List;
30 import java.util.ArrayList;
31 
32 /**
33  * A button designed to be used for the on-screen shutter button.
34  * It's currently an {@code ImageView} that can call a delegate when the
35  * pressed state changes.
36  */
37 public class ShutterButton extends ImageView {
38     private static final Log.Tag TAG = new Log.Tag("ShutterButton");
39     public static final float ALPHA_WHEN_ENABLED = 1f;
40     public static final float ALPHA_WHEN_DISABLED = 0.2f;
41     private boolean mTouchEnabled = true;
42     private TouchCoordinate mTouchCoordinate;
43     /**
44      * A callback to be invoked when a ShutterButton's pressed state changes.
45      */
46     public interface OnShutterButtonListener {
47         /**
48          * Called when a ShutterButton has been pressed.
49          *
50          * @param pressed The ShutterButton that was pressed.
51          */
onShutterButtonFocus(boolean pressed)52         void onShutterButtonFocus(boolean pressed);
onShutterCoordinate(TouchCoordinate coord)53         void onShutterCoordinate(TouchCoordinate coord);
onShutterButtonClick()54         void onShutterButtonClick();
55     }
56 
57     private List<OnShutterButtonListener> mListeners
58         = new ArrayList<OnShutterButtonListener>();
59     private boolean mOldPressed;
60 
ShutterButton(Context context, AttributeSet attrs)61     public ShutterButton(Context context, AttributeSet attrs) {
62         super(context, attrs);
63     }
64 
65     /**
66      * Add an {@link OnShutterButtonListener} to a set of listeners.
67      */
addOnShutterButtonListener(OnShutterButtonListener listener)68     public void addOnShutterButtonListener(OnShutterButtonListener listener) {
69         if (!mListeners.contains(listener)) {
70             mListeners.add(listener);
71         }
72     }
73 
74     /**
75      * Remove an {@link OnShutterButtonListener} from a set of listeners.
76      */
removeOnShutterButtonListener(OnShutterButtonListener listener)77     public void removeOnShutterButtonListener(OnShutterButtonListener listener) {
78         if (mListeners.contains(listener)) {
79             mListeners.remove(listener);
80         }
81     }
82 
83     @Override
dispatchTouchEvent(MotionEvent m)84     public boolean dispatchTouchEvent(MotionEvent m) {
85         if (mTouchEnabled) {
86             if (m.getActionMasked() == MotionEvent.ACTION_UP) {
87                 mTouchCoordinate = new TouchCoordinate(m.getX(), m.getY(), this.getMeasuredWidth(),
88                         this.getMeasuredHeight());
89             }
90             return super.dispatchTouchEvent(m);
91         } else {
92             return false;
93         }
94     }
95 
enableTouch(boolean enable)96     public void enableTouch(boolean enable) {
97         mTouchEnabled = enable;
98     }
99 
100     /**
101      * Hook into the drawable state changing to get changes to isPressed -- the
102      * onPressed listener doesn't always get called when the pressed state
103      * changes.
104      */
105     @Override
drawableStateChanged()106     protected void drawableStateChanged() {
107         super.drawableStateChanged();
108         final boolean pressed = isPressed();
109         if (pressed != mOldPressed) {
110             if (!pressed) {
111                 // When pressing the physical camera button the sequence of
112                 // events is:
113                 //    focus pressed, optional camera pressed, focus released.
114                 // We want to emulate this sequence of events with the shutter
115                 // button. When clicking using a trackball button, the view
116                 // system changes the drawable state before posting click
117                 // notification, so the sequence of events is:
118                 //    pressed(true), optional click, pressed(false)
119                 // When clicking using touch events, the view system changes the
120                 // drawable state after posting click notification, so the
121                 // sequence of events is:
122                 //    pressed(true), pressed(false), optional click
123                 // Since we're emulating the physical camera button, we want to
124                 // have the same order of events. So we want the optional click
125                 // callback to be delivered before the pressed(false) callback.
126                 //
127                 // To do this, we delay the posting of the pressed(false) event
128                 // slightly by pushing it on the event queue. This moves it
129                 // after the optional click notification, so our client always
130                 // sees events in this sequence:
131                 //     pressed(true), optional click, pressed(false)
132                 post(new Runnable() {
133                     @Override
134                     public void run() {
135                         callShutterButtonFocus(pressed);
136                     }
137                 });
138             } else {
139                 callShutterButtonFocus(pressed);
140             }
141             mOldPressed = pressed;
142         }
143     }
144 
callShutterButtonFocus(boolean pressed)145     private void callShutterButtonFocus(boolean pressed) {
146         for (OnShutterButtonListener listener : mListeners) {
147             listener.onShutterButtonFocus(pressed);
148         }
149     }
150 
151     @Override
performClick()152     public boolean performClick() {
153         boolean result = super.performClick();
154         if (getVisibility() == View.VISIBLE) {
155             for (OnShutterButtonListener listener : mListeners) {
156                 listener.onShutterCoordinate(mTouchCoordinate);
157                 mTouchCoordinate = null;
158                 listener.onShutterButtonClick();
159             }
160         }
161         return result;
162     }
163 }
164