1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.music;
18 
19 import android.content.Context;
20 import android.os.SystemClock;
21 import android.util.AttributeSet;
22 import android.view.KeyEvent;
23 import android.view.MotionEvent;
24 import android.view.View;
25 import android.widget.ImageButton;
26 
27 /**
28  * A button that will repeatedly call a 'listener' method
29  * as long as the button is pressed.
30  */
31 public class RepeatingImageButton extends ImageButton {
32     private long mStartTime;
33     private int mRepeatCount;
34     private RepeatListener mListener;
35     private long mInterval = 500;
36 
RepeatingImageButton(Context context)37     public RepeatingImageButton(Context context) {
38         this(context, null);
39     }
40 
RepeatingImageButton(Context context, AttributeSet attrs)41     public RepeatingImageButton(Context context, AttributeSet attrs) {
42         this(context, attrs, android.R.attr.imageButtonStyle);
43     }
44 
RepeatingImageButton(Context context, AttributeSet attrs, int defStyle)45     public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
46         super(context, attrs, defStyle);
47         setFocusable(true);
48         setLongClickable(true);
49     }
50 
51     /**
52      * Sets the listener to be called while the button is pressed and
53      * the interval in milliseconds with which it will be called.
54      * @param l The listener that will be called
55      * @param interval The interval in milliseconds for calls
56      */
setRepeatListener(RepeatListener l, long interval)57     public void setRepeatListener(RepeatListener l, long interval) {
58         mListener = l;
59         mInterval = interval;
60     }
61 
62     @Override
performLongClick()63     public boolean performLongClick() {
64         mStartTime = SystemClock.elapsedRealtime();
65         mRepeatCount = 0;
66         post(mRepeater);
67         return true;
68     }
69 
70     @Override
onTouchEvent(MotionEvent event)71     public boolean onTouchEvent(MotionEvent event) {
72         if (event.getAction() == MotionEvent.ACTION_UP) {
73             // remove the repeater, but call the hook one more time
74             removeCallbacks(mRepeater);
75             if (mStartTime != 0) {
76                 doRepeat(true);
77                 mStartTime = 0;
78             }
79         }
80         return super.onTouchEvent(event);
81     }
82 
83     @Override
onKeyDown(int keyCode, KeyEvent event)84     public boolean onKeyDown(int keyCode, KeyEvent event) {
85         switch (keyCode) {
86             case KeyEvent.KEYCODE_DPAD_CENTER:
87             case KeyEvent.KEYCODE_ENTER:
88                 // need to call super to make long press work, but return
89                 // true so that the application doesn't get the down event.
90                 super.onKeyDown(keyCode, event);
91                 return true;
92         }
93         return super.onKeyDown(keyCode, event);
94     }
95 
96     @Override
onKeyUp(int keyCode, KeyEvent event)97     public boolean onKeyUp(int keyCode, KeyEvent event) {
98         switch (keyCode) {
99             case KeyEvent.KEYCODE_DPAD_CENTER:
100             case KeyEvent.KEYCODE_ENTER:
101                 // remove the repeater, but call the hook one more time
102                 removeCallbacks(mRepeater);
103                 if (mStartTime != 0) {
104                     doRepeat(true);
105                     mStartTime = 0;
106                 }
107         }
108         return super.onKeyUp(keyCode, event);
109     }
110 
111     private Runnable mRepeater = new Runnable() {
112         public void run() {
113             doRepeat(false);
114             if (isPressed()) {
115                 postDelayed(this, mInterval);
116             }
117         }
118     };
119 
doRepeat(boolean last)120     private void doRepeat(boolean last) {
121         long now = SystemClock.elapsedRealtime();
122         if (mListener != null) {
123             mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
124         }
125     }
126 
127     public interface RepeatListener {
128         /**
129          * This method will be called repeatedly at roughly the interval
130          * specified in setRepeatListener(), for as long as the button
131          * is pressed.
132          * @param v The button as a View.
133          * @param duration The number of milliseconds the button has been pressed so far.
134          * @param repeatcount The number of previous calls in this sequence.
135          * If this is going to be the last call in this sequence (i.e. the user
136          * just stopped pressing the button), the value will be -1.
137          */
onRepeat(View v, long duration, int repeatcount)138         void onRepeat(View v, long duration, int repeatcount);
139     }
140 }
141