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