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