1792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/*
2792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
4792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * you may not use this file except in compliance with the License.
6792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * You may obtain a copy of the License at
7792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
8792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
10792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * See the License for the specific language governing permissions and
14792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * limitations under the License.
15792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
16792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpackage com.android.music;
18792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Context;
20792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.AttributeSet;
22792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.KeyEvent;
23792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.MotionEvent;
24792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.View;
25792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.ImageButton;
26792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
27792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
28792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * A button that will repeatedly call a 'listener' method
29792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * as long as the button is pressed.
30792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
31792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class RepeatingImageButton extends ImageButton {
32792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
33792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long mStartTime;
34792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mRepeatCount;
35792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private RepeatListener mListener;
36792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long mInterval = 500;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public RepeatingImageButton(Context context) {
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        this(context, null);
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public RepeatingImageButton(Context context, AttributeSet attrs) {
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        this(context, attrs, android.R.attr.imageButtonStyle);
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
46792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super(context, attrs, defStyle);
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setFocusable(true);
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setLongClickable(true);
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
53792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Sets the listener to be called while the button is pressed and
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the interval in milliseconds with which it will be called.
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param l The listener that will be called
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param interval The interval in milliseconds for calls
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatListener(RepeatListener l, long interval) {
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mListener = l;
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mInterval = interval;
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean performLongClick() {
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mStartTime = SystemClock.elapsedRealtime();
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mRepeatCount = 0;
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        post(mRepeater);
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onTouchEvent(MotionEvent event) {
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (event.getAction() == MotionEvent.ACTION_UP) {
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // remove the repeater, but call the hook one more time
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeCallbacks(mRepeater);
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mStartTime != 0) {
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doRepeat(true);
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mStartTime = 0;
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return super.onTouchEvent(event);
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
8559316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen    public boolean onKeyDown(int keyCode, KeyEvent event) {
8659316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen        switch (keyCode) {
8759316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen            case KeyEvent.KEYCODE_DPAD_CENTER:
8859316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen            case KeyEvent.KEYCODE_ENTER:
8959316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen                // need to call super to make long press work, but return
9059316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen                // true so that the application doesn't get the down event.
9159316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen                super.onKeyDown(keyCode, event);
9259316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen                return true;
9359316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen        }
9459316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen        return super.onKeyDown(keyCode, event);
9559316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen    }
9659316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen
9759316fd90ed4d1ef804c8cabfd12d86e6340c22dMarco Nelissen    @Override
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        switch (keyCode) {
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        case KeyEvent.KEYCODE_DPAD_CENTER:
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        case KeyEvent.KEYCODE_ENTER:
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // remove the repeater, but call the hook one more time
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeCallbacks(mRepeater);
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mStartTime != 0) {
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doRepeat(true);
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mStartTime = 0;
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return super.onKeyUp(keyCode, event);
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Runnable mRepeater = new Runnable() {
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void run() {
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            doRepeat(false);
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPressed()) {
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                postDelayed(this, mInterval);
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private  void doRepeat(boolean last) {
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        long now = SystemClock.elapsedRealtime();
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mListener != null) {
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public interface RepeatListener {
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        /**
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * This method will be called repeatedly at roughly the interval
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * specified in setRepeatListener(), for as long as the button
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * is pressed.
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * @param v The button as a View.
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * @param duration The number of milliseconds the button has been pressed so far.
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * @param repeatcount The number of previous calls in this sequence.
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * If this is going to be the last call in this sequence (i.e. the user
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * just stopped pressing the button), the value will be -1.
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         */
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        void onRepeat(View v, long duration, int repeatcount);
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
142