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