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.cyanogenmod.eleven;
14 import android.content.Context;
15 import android.content.Intent;
16 import android.media.AudioManager;
17 import android.os.Handler;
18 import android.os.Message;
19 import android.os.PowerManager;
20 import android.os.PowerManager.WakeLock;
21 import android.support.v4.content.WakefulBroadcastReceiver;
22 import android.util.Log;
23 import android.view.KeyEvent;
25 import com.cyanogenmod.eleven.ui.activities.HomeActivity;
28 * Used to control headset playback.
29 * Single press: pause/resume
30 * Double press: next track
31 * Triple press: previous track
32 * Long press: voice search
34 public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver {
35 private static final boolean DEBUG = false;
36 private static final String TAG = "MediaButtonIntentReceiver";
38 private static final int MSG_LONGPRESS_TIMEOUT = 1;
39 private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2;
41 private static final int LONG_PRESS_DELAY = 1000;
42 private static final int DOUBLE_CLICK = 800;
44 private static WakeLock mWakeLock = null;
45 private static int mClickCounter = 0;
46 private static long mLastClickTime = 0;
47 private static boolean mDown = false;
48 private static boolean mLaunched = false;
50 private static Handler mHandler = new Handler() {
56 public void handleMessage(final Message msg) {
58 case MSG_LONGPRESS_TIMEOUT:
59 if (DEBUG) Log.v(TAG, "Handling longpress timeout, launched " + mLaunched);
61 final Context context = (Context)msg.obj;
62 final Intent i = new Intent();
63 i.setClass(context, HomeActivity.class);
64 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
65 context.startActivity(i);
70 case MSG_HEADSET_DOUBLE_CLICK_TIMEOUT:
71 final int clickCount = msg.arg1;
74 if (DEBUG) Log.v(TAG, "Handling headset click, count = " + clickCount);
76 case 1: command = MusicPlaybackService.CMDTOGGLEPAUSE; break;
77 case 2: command = MusicPlaybackService.CMDNEXT; break;
78 case 3: command = MusicPlaybackService.CMDPREVIOUS; break;
79 default: command = null; break;
82 if (command != null) {
83 final Context context = (Context)msg.obj;
84 startService(context, command);
88 releaseWakeLockIfHandlerIdle();
96 public void onReceive(final Context context, final Intent intent) {
97 if (DEBUG) Log.v(TAG, "Received intent: " + intent);
98 final String intentAction = intent.getAction();
99 if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) {
100 startService(context, MusicPlaybackService.CMDPAUSE);
101 } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
102 final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
107 final int keycode = event.getKeyCode();
108 final int action = event.getAction();
109 final long eventtime = event.getEventTime();
111 String command = null;
113 case KeyEvent.KEYCODE_MEDIA_STOP:
114 command = MusicPlaybackService.CMDSTOP;
116 case KeyEvent.KEYCODE_HEADSETHOOK:
117 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
118 command = MusicPlaybackService.CMDTOGGLEPAUSE;
120 case KeyEvent.KEYCODE_MEDIA_NEXT:
121 command = MusicPlaybackService.CMDNEXT;
123 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
124 command = MusicPlaybackService.CMDPREVIOUS;
126 case KeyEvent.KEYCODE_MEDIA_PAUSE:
127 command = MusicPlaybackService.CMDPAUSE;
129 case KeyEvent.KEYCODE_MEDIA_PLAY:
130 command = MusicPlaybackService.CMDPLAY;
133 if (command != null) {
134 if (action == KeyEvent.ACTION_DOWN) {
136 if (MusicPlaybackService.CMDTOGGLEPAUSE.equals(command)
137 || MusicPlaybackService.CMDPLAY.equals(command)) {
138 if (mLastClickTime != 0
139 && eventtime - mLastClickTime > LONG_PRESS_DELAY) {
140 acquireWakeLockAndSendMessage(context,
141 mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context), 0);
144 } else if (event.getRepeatCount() == 0) {
145 // Only consider the first event in a sequence, not the repeat events,
146 // so that we don't trigger in cases where the first event went to
147 // a different app (e.g. when the user ends a phone call by
148 // long pressing the headset button)
150 // The service may or may not be running, but we need to send it
152 if (keycode == KeyEvent.KEYCODE_HEADSETHOOK) {
153 if (eventtime - mLastClickTime >= DOUBLE_CLICK) {
158 if (DEBUG) Log.v(TAG, "Got headset click, count = " + mClickCounter);
159 mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT);
161 Message msg = mHandler.obtainMessage(
162 MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context);
164 long delay = mClickCounter < 3 ? DOUBLE_CLICK : 0;
165 if (mClickCounter >= 3) {
168 mLastClickTime = eventtime;
169 acquireWakeLockAndSendMessage(context, msg, delay);
171 startService(context, command);
177 mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT);
180 if (isOrderedBroadcast()) {
183 releaseWakeLockIfHandlerIdle();
188 private static void startService(Context context, String command) {
189 final Intent i = new Intent(context, MusicPlaybackService.class);
190 i.setAction(MusicPlaybackService.SERVICECMD);
191 i.putExtra(MusicPlaybackService.CMDNAME, command);
192 i.putExtra(MusicPlaybackService.FROM_MEDIA_BUTTON, true);
193 startWakefulService(context, i);
196 private static void acquireWakeLockAndSendMessage(Context context, Message msg, long delay) {
197 if (mWakeLock == null) {
198 Context appContext = context.getApplicationContext();
199 PowerManager pm = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE);
200 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Eleven headset button");
201 mWakeLock.setReferenceCounted(false);
203 if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what);
204 // Make sure we don't indefinitely hold the wake lock under any circumstances
205 mWakeLock.acquire(10000);
207 mHandler.sendMessageDelayed(msg, delay);
210 private static void releaseWakeLockIfHandlerIdle() {
211 if (mHandler.hasMessages(MSG_LONGPRESS_TIMEOUT)
212 || mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) {
213 if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock");
217 if (mWakeLock != null) {
218 if (DEBUG) Log.v(TAG, "Releasing wake lock");