1b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project/* 2b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 4b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * you may not use this file except in compliance with the License. 6b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * You may obtain a copy of the License at 7b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 8b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 10b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * See the License for the specific language governing permissions and 14b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * limitations under the License. 15b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 16b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 17b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectpackage com.android.camera; 18b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 19b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.Context; 20b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.util.AttributeSet; 215da800f7a1427066a310a41964d780924c1f1a10Michael Kolbimport android.view.MotionEvent; 2254ed58a3351e0558eb06b59441b1c3875feaf886Angus Kongimport android.view.View; 23b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.widget.ImageView; 24b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 25b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project/** 26b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * A button designed to be used for the on-screen shutter button. 27271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * It's currently an {@code ImageView} that can call a delegate when the 28271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * pressed state changes. 29b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 3030e2c49eedfbce51be7458161829a750f809d56dWu-cheng Lipublic class ShutterButton extends ImageView { 315da800f7a1427066a310a41964d780924c1f1a10Michael Kolb 325da800f7a1427066a310a41964d780924c1f1a10Michael Kolb private boolean mTouchEnabled = true; 335da800f7a1427066a310a41964d780924c1f1a10Michael Kolb 34b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 35271b3095b9f763421c0547109da9de774795072dChih-Chung Chang * A callback to be invoked when a ShutterButton's pressed state changes. 36b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 37b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public interface OnShutterButtonListener { 38b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 39b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Called when a ShutterButton has been pressed. 40b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 411bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li * @param pressed The ShutterButton that was pressed. 42b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 431bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li void onShutterButtonFocus(boolean pressed); 441bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li void onShutterButtonClick(); 45b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 46b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 47b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private OnShutterButtonListener mListener; 48b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private boolean mOldPressed; 49b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 50b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public ShutterButton(Context context, AttributeSet attrs) { 51b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project super(context, attrs); 52b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 53b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 54b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public void setOnShutterButtonListener(OnShutterButtonListener listener) { 55b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project mListener = listener; 56b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 57b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 585da800f7a1427066a310a41964d780924c1f1a10Michael Kolb @Override 595da800f7a1427066a310a41964d780924c1f1a10Michael Kolb public boolean dispatchTouchEvent(MotionEvent m) { 605da800f7a1427066a310a41964d780924c1f1a10Michael Kolb if (mTouchEnabled) { 615da800f7a1427066a310a41964d780924c1f1a10Michael Kolb return super.dispatchTouchEvent(m); 625da800f7a1427066a310a41964d780924c1f1a10Michael Kolb } else { 635da800f7a1427066a310a41964d780924c1f1a10Michael Kolb return false; 645da800f7a1427066a310a41964d780924c1f1a10Michael Kolb } 655da800f7a1427066a310a41964d780924c1f1a10Michael Kolb } 665da800f7a1427066a310a41964d780924c1f1a10Michael Kolb 675da800f7a1427066a310a41964d780924c1f1a10Michael Kolb public void enableTouch(boolean enable) { 685da800f7a1427066a310a41964d780924c1f1a10Michael Kolb mTouchEnabled = enable; 695da800f7a1427066a310a41964d780924c1f1a10Michael Kolb } 705da800f7a1427066a310a41964d780924c1f1a10Michael Kolb 71b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 72b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Hook into the drawable state changing to get changes to isPressed -- the 73e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang * onPressed listener doesn't always get called when the pressed state 74e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang * changes. 75b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 76b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project @Override 77b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project protected void drawableStateChanged() { 78b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project super.drawableStateChanged(); 79b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project final boolean pressed = isPressed(); 80b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (pressed != mOldPressed) { 81b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (!pressed) { 82e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // When pressing the physical camera button the sequence of 83e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // events is: 84b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // focus pressed, optional camera pressed, focus released. 85e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // We want to emulate this sequence of events with the shutter 86e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // button. When clicking using a trackball button, the view 878dc2b940fa574e22839c70ed0ee6ad6e903c2932Pin Ting // system changes the drawable state before posting click 88e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // notification, so the sequence of events is: 89b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // pressed(true), optional click, pressed(false) 90b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // When clicking using touch events, the view system changes the 91e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // drawable state after posting click notification, so the 92e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // sequence of events is: 93b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // pressed(true), pressed(false), optional click 94e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // Since we're emulating the physical camera button, we want to 95e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // have the same order of events. So we want the optional click 96e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // callback to be delivered before the pressed(false) callback. 97b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // 98e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // To do this, we delay the posting of the pressed(false) event 99e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // slightly by pushing it on the event queue. This moves it 100e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // after the optional click notification, so our client always 101e38e6257ba032e80154c9a8a7ee62b6a98f02b8cChih-Chung Chang // sees events in this sequence: 102b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // pressed(true), optional click, pressed(false) 103b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project post(new Runnable() { 104913f3784d368a5e11fee5d5db2c355ef832685daWu-cheng Li @Override 105b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public void run() { 106b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project callShutterButtonFocus(pressed); 107b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 108b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project }); 109b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } else { 110b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project callShutterButtonFocus(pressed); 111b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 112b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project mOldPressed = pressed; 113b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 114b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 115b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 116b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private void callShutterButtonFocus(boolean pressed) { 117b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (mListener != null) { 1181bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li mListener.onShutterButtonFocus(pressed); 119b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 120b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 121b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 122b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project @Override 123b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public boolean performClick() { 124b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project boolean result = super.performClick(); 12554ed58a3351e0558eb06b59441b1c3875feaf886Angus Kong if (mListener != null && getVisibility() == View.VISIBLE) { 1261bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li mListener.onShutterButtonClick(); 127b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 128b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return result; 129b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 130b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project} 131