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