2 * Copyright (C) 2007 The Android Open Source Project Licensed under the Apache
3 * License, Version 2.0 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 * or agreed to in writing, software distributed under the License is
7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 * KIND, either express or implied. See the License for the specific language
9 * governing permissions and limitations under the License.
12 package com.cyngn.eleven;
14 import android.content.BroadcastReceiver;
15 import android.content.Context;
16 import android.content.Intent;
17 import android.media.AudioManager;
18 import android.os.Handler;
19 import android.os.Message;
20 import android.os.PowerManager;
21 import android.os.PowerManager.WakeLock;
22 import android.support.v4.content.WakefulBroadcastReceiver;
23 import android.util.Log;
24 import android.view.KeyEvent;
26 import com.cyngn.eleven.ui.activities.HomeActivity;
29 * Used to control headset playback.
30 * Single press: pause/resume
31 * Double press: next track
32 * Triple press: previous track
33 * Long press: voice search
35 public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver {
36 private static final boolean DEBUG = false;
37 private static final String TAG = "MediaButtonIntentReceiver";
39 private static final int MSG_LONGPRESS_TIMEOUT = 1;
40 private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2;
42 private static final int LONG_PRESS_DELAY = 1000;
43 private static final int DOUBLE_CLICK = 800;
45 private static WakeLock mWakeLock = null;
46 private static int mClickCounter = 0;
47 private static long mLastClickTime = 0;
48 private static boolean mDown = false;
49 private static boolean mLaunched = false;
51 private static Handler mHandler = new Handler() {
57 public void handleMessage(final Message msg) {
59 case MSG_LONGPRESS_TIMEOUT:
60 if (DEBUG) Log.v(TAG, "Handling longpress timeout, launched " + mLaunched);
62 final Context context = (Context)msg.obj;
63 final Intent i = new Intent();
64 i.setClass(context, HomeActivity.class);
65 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
66 context.startActivity(i);
71 case MSG_HEADSET_DOUBLE_CLICK_TIMEOUT:
72 final int clickCount = msg.arg1;
75 if (DEBUG) Log.v(TAG, "Handling headset click, count = " + clickCount);
77 case 1: command = MusicPlaybackService.CMDTOGGLEPAUSE; break;
78 case 2: command = MusicPlaybackService.CMDNEXT; break;
79 case 3: command = MusicPlaybackService.CMDPREVIOUS; break;
80 default: command = null; break;
83 if (command != null) {
84 final Context context = (Context)msg.obj;
85 startService(context, command);
89 releaseWakeLockIfHandlerIdle();
97 public void onReceive(final Context context, final Intent intent) {
98 if (DEBUG) Log.v(TAG, "Received intent: " + intent);
99 final String intentAction = intent.getAction();
100 if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) {
101 startService(context, MusicPlaybackService.CMDPAUSE);
102 } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
103 final KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
108 final int keycode = event.getKeyCode();
109 final int action = event.getAction();
110 final long eventtime = event.getEventTime();
112 String command = null;
114 case KeyEvent.KEYCODE_MEDIA_STOP:
115 command = MusicPlaybackService.CMDSTOP;
117 case KeyEvent.KEYCODE_HEADSETHOOK:
118 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
119 command = MusicPlaybackService.CMDTOGGLEPAUSE;
121 case KeyEvent.KEYCODE_MEDIA_NEXT:
122 command = MusicPlaybackService.CMDNEXT;
124 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
125 command = MusicPlaybackService.CMDPREVIOUS;
127 case KeyEvent.KEYCODE_MEDIA_PAUSE:
128 command = MusicPlaybackService.CMDPAUSE;
130 case KeyEvent.KEYCODE_MEDIA_PLAY:
131 command = MusicPlaybackService.CMDPLAY;
134 if (command != null) {
135 if (action == KeyEvent.ACTION_DOWN) {
137 if (MusicPlaybackService.CMDTOGGLEPAUSE.equals(command)
138 || MusicPlaybackService.CMDPLAY.equals(command)) {
139 if (mLastClickTime != 0
140 && eventtime - mLastClickTime > LONG_PRESS_DELAY) {
141 acquireWakeLockAndSendMessage(context,
142 mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context), 0);
145 } else if (event.getRepeatCount() == 0) {
146 // Only consider the first event in a sequence, not the repeat events,
147 // so that we don't trigger in cases where the first event went to
148 // a different app (e.g. when the user ends a phone call by
149 // long pressing the headset button)
151 // The service may or may not be running, but we need to send it
153 if (keycode == KeyEvent.KEYCODE_HEADSETHOOK) {
154 if (eventtime - mLastClickTime >= DOUBLE_CLICK) {
159 if (DEBUG) Log.v(TAG, "Got headset click, count = " + mClickCounter);
160 mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT);
162 Message msg = mHandler.obtainMessage(
163 MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context);
165 long delay = mClickCounter < 3 ? DOUBLE_CLICK : 0;
166 if (mClickCounter >= 3) {
169 mLastClickTime = eventtime;
170 acquireWakeLockAndSendMessage(context, msg, delay);
172 startService(context, command);
178 mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT);
181 if (isOrderedBroadcast()) {
184 releaseWakeLockIfHandlerIdle();
189 private static void startService(Context context, String command) {
190 final Intent i = new Intent(context, MusicPlaybackService.class);
191 i.setAction(MusicPlaybackService.SERVICECMD);
192 i.putExtra(MusicPlaybackService.CMDNAME, command);
193 i.putExtra(MusicPlaybackService.FROM_MEDIA_BUTTON, true);
194 startWakefulService(context, i);
197 private static void acquireWakeLockAndSendMessage(Context context, Message msg, long delay) {
198 if (mWakeLock == null) {
199 Context appContext = context.getApplicationContext();
200 PowerManager pm = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE);
201 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Eleven headset button");
202 mWakeLock.setReferenceCounted(false);
204 if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what);
205 // Make sure we don't indefinitely hold the wake lock under any circumstances
206 mWakeLock.acquire(10000);
208 mHandler.sendMessageDelayed(msg, delay);
211 private static void releaseWakeLockIfHandlerIdle() {
212 if (mHandler.hasMessages(MSG_LONGPRESS_TIMEOUT)
213 || mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) {
214 if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock");
218 if (mWakeLock != null) {
219 if (DEBUG) Log.v(TAG, "Releasing wake lock");