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