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.util.AttributeSet; 21 import android.view.MotionEvent; 22 import android.widget.ImageView; 23 24 /** 25 * A button designed to be used for the on-screen shutter button. 26 * It's currently an {@code ImageView} that can call a delegate when the 27 * pressed state changes. 28 */ 29 public class ShutterButton extends ImageView { 30 31 private boolean mTouchEnabled = true; 32 33 /** 34 * A callback to be invoked when a ShutterButton's pressed state changes. 35 */ 36 public interface OnShutterButtonListener { 37 /** 38 * Called when a ShutterButton has been pressed. 39 * 40 * @param pressed The ShutterButton that was pressed. 41 */ 42 void onShutterButtonFocus(boolean pressed); 43 void onShutterButtonClick(); 44 } 45 46 private OnShutterButtonListener mListener; 47 private boolean mOldPressed; 48 49 public ShutterButton(Context context, AttributeSet attrs) { 50 super(context, attrs); 51 } 52 53 public void setOnShutterButtonListener(OnShutterButtonListener listener) { 54 mListener = listener; 55 } 56 57 @Override 58 public boolean dispatchTouchEvent(MotionEvent m) { 59 if (mTouchEnabled) { 60 return super.dispatchTouchEvent(m); 61 } else { 62 return false; 63 } 64 } 65 66 public void enableTouch(boolean enable) { 67 mTouchEnabled = enable; 68 } 69 70 /** 71 * Hook into the drawable state changing to get changes to isPressed -- the 72 * onPressed listener doesn't always get called when the pressed state 73 * changes. 74 */ 75 @Override 76 protected void drawableStateChanged() { 77 super.drawableStateChanged(); 78 final boolean pressed = isPressed(); 79 if (pressed != mOldPressed) { 80 if (!pressed) { 81 // When pressing the physical camera button the sequence of 82 // events is: 83 // focus pressed, optional camera pressed, focus released. 84 // We want to emulate this sequence of events with the shutter 85 // button. When clicking using a trackball button, the view 86 // system changes the drawable state before posting click 87 // notification, so the sequence of events is: 88 // pressed(true), optional click, pressed(false) 89 // When clicking using touch events, the view system changes the 90 // drawable state after posting click notification, so the 91 // sequence of events is: 92 // pressed(true), pressed(false), optional click 93 // Since we're emulating the physical camera button, we want to 94 // have the same order of events. So we want the optional click 95 // callback to be delivered before the pressed(false) callback. 96 // 97 // To do this, we delay the posting of the pressed(false) event 98 // slightly by pushing it on the event queue. This moves it 99 // after the optional click notification, so our client always 100 // sees events in this sequence: 101 // pressed(true), optional click, pressed(false) 102 post(new Runnable() { 103 @Override 104 public void run() { 105 callShutterButtonFocus(pressed); 106 } 107 }); 108 } else { 109 callShutterButtonFocus(pressed); 110 } 111 mOldPressed = pressed; 112 } 113 } 114 115 private void callShutterButtonFocus(boolean pressed) { 116 if (mListener != null) { 117 mListener.onShutterButtonFocus(pressed); 118 } 119 } 120 121 @Override 122 public boolean performClick() { 123 boolean result = super.performClick(); 124 if (mListener != null) { 125 mListener.onShutterButtonClick(); 126 } 127 return result; 128 } 129 } 130