18872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb/* 28872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Copyright (C) 2008 The Android Open Source Project 38872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 48872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Licensed under the Apache License, Version 2.0 (the "License"); 58872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * you may not use this file except in compliance with the License. 68872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * You may obtain a copy of the License at 78872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 88872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * http://www.apache.org/licenses/LICENSE-2.0 98872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Unless required by applicable law or agreed to in writing, software 118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * distributed under the License is distributed on an "AS IS" BASIS, 128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * See the License for the specific language governing permissions and 148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * limitations under the License. 158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpackage com.android.camera; 188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.Context; 208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.util.AttributeSet; 218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.MotionEvent; 228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.View; 238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.widget.ImageView; 248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb/** 268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * A button designed to be used for the on-screen shutter button. 278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * It's currently an {@code ImageView} that can call a delegate when the 288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * pressed state changes. 298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpublic class ShutterButton extends ImageView { 318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mTouchEnabled = true; 338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * A callback to be invoked when a ShutterButton's pressed state changes. 368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public interface OnShutterButtonListener { 388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Called when a ShutterButton has been pressed. 408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @param pressed The ShutterButton that was pressed. 428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb void onShutterButtonFocus(boolean pressed); 448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb void onShutterButtonClick(); 458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private OnShutterButtonListener mListener; 488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mOldPressed; 498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public ShutterButton(Context context, AttributeSet attrs) { 518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb super(context, attrs); 528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setOnShutterButtonListener(OnShutterButtonListener listener) { 558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mListener = listener; 568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public boolean dispatchTouchEvent(MotionEvent m) { 608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mTouchEnabled) { 618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return super.dispatchTouchEvent(m); 628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return false; 648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void enableTouch(boolean enable) { 688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTouchEnabled = enable; 698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Hook into the drawable state changing to get changes to isPressed -- the 738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * onPressed listener doesn't always get called when the pressed state 748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * changes. 758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb protected void drawableStateChanged() { 788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb super.drawableStateChanged(); 798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb final boolean pressed = isPressed(); 808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (pressed != mOldPressed) { 818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (!pressed) { 828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // When pressing the physical camera button the sequence of 838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // events is: 848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // focus pressed, optional camera pressed, focus released. 858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // We want to emulate this sequence of events with the shutter 868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // button. When clicking using a trackball button, the view 878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // system changes the drawable state before posting click 888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // notification, so the sequence of events is: 898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // pressed(true), optional click, pressed(false) 908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // When clicking using touch events, the view system changes the 918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // drawable state after posting click notification, so the 928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // sequence of events is: 938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // pressed(true), pressed(false), optional click 948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // Since we're emulating the physical camera button, we want to 958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // have the same order of events. So we want the optional click 968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // callback to be delivered before the pressed(false) callback. 978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // 988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // To do this, we delay the posting of the pressed(false) event 998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // slightly by pushing it on the event queue. This moves it 1008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // after the optional click notification, so our client always 1018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // sees events in this sequence: 1028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // pressed(true), optional click, pressed(false) 1038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb post(new Runnable() { 1048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 1058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void run() { 1068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb callShutterButtonFocus(pressed); 1078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb }); 1098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 1108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb callShutterButtonFocus(pressed); 1118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOldPressed = pressed; 1138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void callShutterButtonFocus(boolean pressed) { 1178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mListener != null) { 1188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mListener.onShutterButtonFocus(pressed); 1198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 1238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public boolean performClick() { 1248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb boolean result = super.performClick(); 1258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mListener != null && getVisibility() == View.VISIBLE) { 1268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mListener.onShutterButtonClick(); 1278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return result; 1298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb} 131