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 
33     private long mStartTime;
34     private int mRepeatCount;
35     private RepeatListener mListener;
36     private long mInterval = 500;
37 
RepeatingImageButton(Context context)38     public RepeatingImageButton(Context context) {
39         this(context, null);
40     }
41 
RepeatingImageButton(Context context, AttributeSet attrs)42     public RepeatingImageButton(Context context, AttributeSet attrs) {
43         this(context, attrs, android.R.attr.imageButtonStyle);
44     }
45 
RepeatingImageButton(Context context, AttributeSet attrs, int defStyle)46     public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
47         super(context, attrs, defStyle);
48         setFocusable(true);
49         setLongClickable(true);
50     }
51 
52     /**
53      * Sets the listener to be called while the button is pressed and
54      * the interval in milliseconds with which it will be called.
55      * @param l The listener that will be called
56      * @param interval The interval in milliseconds for calls
57      */
setRepeatListener(RepeatListener l, long interval)58     public void setRepeatListener(RepeatListener l, long interval) {
59         mListener = l;
60         mInterval = interval;
61     }
62 
63     @Override
performLongClick()64     public boolean performLongClick() {
65         mStartTime = SystemClock.elapsedRealtime();
66         mRepeatCount = 0;
67         post(mRepeater);
68         return true;
69     }
70 
71     @Override
onTouchEvent(MotionEvent event)72     public boolean onTouchEvent(MotionEvent event) {
73         if (event.getAction() == MotionEvent.ACTION_UP) {
74             // remove the repeater, but call the hook one more time
75             removeCallbacks(mRepeater);
76             if (mStartTime != 0) {
77                 doRepeat(true);
78                 mStartTime = 0;
79             }
80         }
81         return super.onTouchEvent(event);
82     }
83 
84     @Override
onKeyDown(int keyCode, KeyEvent event)85     public boolean onKeyDown(int keyCode, KeyEvent event) {
86         switch (keyCode) {
87             case KeyEvent.KEYCODE_DPAD_CENTER:
88             case KeyEvent.KEYCODE_ENTER:
89                 // need to call super to make long press work, but return
90                 // true so that the application doesn't get the down event.
91                 super.onKeyDown(keyCode, event);
92                 return true;
93         }
94         return super.onKeyDown(keyCode, event);
95     }
96 
97     @Override
onKeyUp(int keyCode, KeyEvent event)98     public boolean onKeyUp(int keyCode, KeyEvent event) {
99         switch (keyCode) {
100         case KeyEvent.KEYCODE_DPAD_CENTER:
101         case KeyEvent.KEYCODE_ENTER:
102             // remove the repeater, but call the hook one more time
103             removeCallbacks(mRepeater);
104             if (mStartTime != 0) {
105                 doRepeat(true);
106                 mStartTime = 0;
107             }
108         }
109         return super.onKeyUp(keyCode, event);
110     }
111 
112     private Runnable mRepeater = new Runnable() {
113         public void run() {
114             doRepeat(false);
115             if (isPressed()) {
116                 postDelayed(this, mInterval);
117             }
118         }
119     };
120 
doRepeat(boolean last)121     private  void doRepeat(boolean last) {
122         long now = SystemClock.elapsedRealtime();
123         if (mListener != null) {
124             mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
125         }
126     }
127 
128     public interface RepeatListener {
129         /**
130          * This method will be called repeatedly at roughly the interval
131          * specified in setRepeatListener(), for as long as the button
132          * is pressed.
133          * @param v The button as a View.
134          * @param duration The number of milliseconds the button has been pressed so far.
135          * @param repeatcount The number of previous calls in this sequence.
136          * If this is going to be the last call in this sequence (i.e. the user
137          * just stopped pressing the button), the value will be -1.
138          */
onRepeat(View v, long duration, int repeatcount)139         void onRepeat(View v, long duration, int repeatcount);
140     }
141 }
142