Skip to content

Commit c680222

Browse files
committed
Optimize how AudioService receives media button events
AudioService maintains a stack of registered media button event receivers. This change modifies the broadcasters of ACTION_MEDIA_BUTTON intents let AudioService directly handle the corresponding key event instead of trapping the intent sent by PhoneWindowManager, KeyguardViewBase and PhoneFallbackEventHandler. Because the key event may be sent through a PendingIntent, AudioService now also implements the OnFinished interface to be notified when the event was consumed so it can release the wake lock held if it was held when the key event needed to be sent (see where PassHeadsetKey was instanciated in PhoneWindowManager). Change-Id: I2e8614df94af9d54edbf714ef443cc372d21827a
1 parent d6be37d commit c680222

File tree

5 files changed

+154
-72
lines changed

5 files changed

+154
-72
lines changed

media/java/android/media/AudioService.java

Lines changed: 100 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import static android.media.AudioManager.RINGER_MODE_SILENT;
2222
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
2323

24+
import android.app.Activity;
2425
import android.app.ActivityManagerNative;
2526
import android.app.KeyguardManager;
2627
import android.app.PendingIntent;
2728
import android.app.PendingIntent.CanceledException;
29+
import android.app.PendingIntent.OnFinished;
2830
import android.bluetooth.BluetoothA2dp;
2931
import android.bluetooth.BluetoothAdapter;
3032
import android.bluetooth.BluetoothClass;
@@ -48,6 +50,7 @@
4850
import android.os.IBinder;
4951
import android.os.Looper;
5052
import android.os.Message;
53+
import android.os.PowerManager;
5154
import android.os.RemoteException;
5255
import android.os.ServiceManager;
5356
import android.os.SystemProperties;
@@ -85,7 +88,7 @@
8588
*
8689
* @hide
8790
*/
88-
public class AudioService extends IAudioService.Stub {
91+
public class AudioService extends IAudioService.Stub implements OnFinished {
8992

9093
private static final String TAG = "AudioService";
9194

@@ -289,10 +292,6 @@ public void onError(int error) {
289292
// Broadcast receiver for device connections intent broadcasts
290293
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
291294

292-
// Broadcast receiver for media button broadcasts (separate from mReceiver to
293-
// independently change its priority)
294-
private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
295-
296295
// Used to alter media button redirection when the phone is ringing.
297296
private boolean mIsRinging = false;
298297

@@ -383,6 +382,9 @@ public AudioService(Context context) {
383382
mVoiceCapable = mContext.getResources().getBoolean(
384383
com.android.internal.R.bool.config_voice_capable);
385384

385+
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
386+
mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mediaKeyEvent");
387+
386388
// Intialized volume
387389
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
388390
"ro.config.vc_call_vol_steps",
@@ -434,13 +436,6 @@ public AudioService(Context context) {
434436
pkgFilter.addDataScheme("package");
435437
context.registerReceiver(mReceiver, pkgFilter);
436438

437-
// Register for media button intent broadcasts.
438-
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
439-
// Workaround for bug on priority setting
440-
//intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
441-
intentFilter.setPriority(Integer.MAX_VALUE);
442-
context.registerReceiver(mMediaButtonReceiver, intentFilter);
443-
444439
// Register for phone state monitoring
445440
TelephonyManager tmgr = (TelephonyManager)
446441
context.getSystemService(Context.TELEPHONY_SERVICE);
@@ -3492,54 +3487,109 @@ public void unregisterAudioFocusClient(String clientId) {
34923487
//==========================================================================================
34933488
// RemoteControl
34943489
//==========================================================================================
3490+
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
3491+
dispatchMediaKeyEvent(keyEvent, false /*needWakeLock*/);
3492+
}
3493+
3494+
public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
3495+
dispatchMediaKeyEvent(keyEvent, true /*needWakeLock*/);
3496+
}
3497+
34953498
/**
3496-
* Receiver for media button intents. Handles the dispatching of the media button event
3497-
* to one of the registered listeners, or if there was none, resumes the intent broadcast
3498-
* to the rest of the system.
3499+
* Handles the dispatching of the media button events to one of the registered listeners,
3500+
* or if there was none, broadcast a ACTION_MEDIA_BUTTON intent to the rest of the system.
34993501
*/
3500-
private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
3501-
@Override
3502-
public void onReceive(Context context, Intent intent) {
3503-
String action = intent.getAction();
3504-
if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) {
3502+
private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3503+
// sanity check on the incoming key event
3504+
if (!isValidMediaKeyEvent(keyEvent)) {
3505+
Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
3506+
return;
3507+
}
3508+
// event filtering
3509+
synchronized(mRingingLock) {
3510+
if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
3511+
(getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
3512+
(getMode() == AudioSystem.MODE_RINGTONE) ) {
35053513
return;
35063514
}
3507-
KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
3508-
if (event != null) {
3509-
// if in a call or ringing, do not break the current phone app behavior
3510-
// TODO modify this to let the phone app specifically get the RC focus
3511-
// add modify the phone app to take advantage of the new API
3512-
synchronized(mRingingLock) {
3513-
if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
3514-
(getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
3515-
(getMode() == AudioSystem.MODE_RINGTONE) ) {
3516-
return;
3517-
}
3515+
}
3516+
if (needWakeLock) {
3517+
mMediaEventWakeLock.acquire();
3518+
}
3519+
Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3520+
keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
3521+
synchronized(mRCStack) {
3522+
if (!mRCStack.empty()) {
3523+
// send the intent that was registered by the client
3524+
try {
3525+
mRCStack.peek().mMediaIntent.send(mContext,
3526+
needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
3527+
keyIntent, AudioService.this, mAudioHandler);
3528+
} catch (CanceledException e) {
3529+
Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
3530+
e.printStackTrace();
35183531
}
3519-
synchronized(mRCStack) {
3520-
if (!mRCStack.empty()) {
3521-
// create a new intent to fill in the extras of the registered PendingIntent
3522-
Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
3523-
Bundle extras = intent.getExtras();
3524-
if (extras != null) {
3525-
targetedIntent.putExtras(extras);
3526-
// trap the current broadcast
3527-
abortBroadcast();
3528-
//Log.v(TAG, " Sending intent" + targetedIntent);
3529-
// send the intent that was registered by the client
3530-
try {
3531-
mRCStack.peek().mMediaIntent.send(context, 0, targetedIntent);
3532-
} catch (CanceledException e) {
3533-
Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
3534-
e.printStackTrace();
3535-
}
3536-
}
3537-
}
3532+
} else {
3533+
// legacy behavior when nobody registered their media button event receiver
3534+
// through AudioManager
3535+
if (needWakeLock) {
3536+
keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
35383537
}
3538+
mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
3539+
mAudioHandler, Activity.RESULT_OK, null, null);
35393540
}
35403541
}
35413542
}
35423543

3544+
private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
3545+
if (keyEvent == null) {
3546+
return false;
3547+
}
3548+
final int keyCode = keyEvent.getKeyCode();
3549+
switch (keyCode) {
3550+
case KeyEvent.KEYCODE_MUTE:
3551+
case KeyEvent.KEYCODE_HEADSETHOOK:
3552+
case KeyEvent.KEYCODE_MEDIA_PLAY:
3553+
case KeyEvent.KEYCODE_MEDIA_PAUSE:
3554+
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
3555+
case KeyEvent.KEYCODE_MEDIA_STOP:
3556+
case KeyEvent.KEYCODE_MEDIA_NEXT:
3557+
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
3558+
case KeyEvent.KEYCODE_MEDIA_REWIND:
3559+
case KeyEvent.KEYCODE_MEDIA_RECORD:
3560+
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
3561+
case KeyEvent.KEYCODE_MEDIA_CLOSE:
3562+
case KeyEvent.KEYCODE_MEDIA_EJECT:
3563+
break;
3564+
default:
3565+
return false;
3566+
}
3567+
return true;
3568+
}
3569+
3570+
private PowerManager.WakeLock mMediaEventWakeLock;
3571+
3572+
private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
3573+
3574+
// only set when wakelock was acquired, no need to check value when received
3575+
private static final String EXTRA_WAKELOCK_ACQUIRED =
3576+
"android.media.AudioService.WAKELOCK_ACQUIRED";
3577+
3578+
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
3579+
int resultCode, String resultData, Bundle resultExtras) {
3580+
if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
3581+
mMediaEventWakeLock.release();
3582+
}
3583+
}
3584+
3585+
BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
3586+
public void onReceive(Context context, Intent intent) {
3587+
if (intent.getExtras().containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
3588+
mMediaEventWakeLock.release();
3589+
}
3590+
}
3591+
};
3592+
35433593
private final Object mCurrentRcLock = new Object();
35443594
/**
35453595
* The one remote control client which will receive a request for display information.

media/java/android/media/IAudioService.aidl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import android.media.IRemoteControlClient;
2323
import android.media.IRemoteControlDisplay;
2424
import android.media.IRingtonePlayer;
2525
import android.net.Uri;
26+
import android.view.KeyEvent;
2627

2728
/**
2829
* {@hide}
@@ -102,6 +103,9 @@ interface IAudioService {
102103

103104
void unregisterAudioFocusClient(String clientId);
104105

106+
oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
107+
void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
108+
105109
oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
106110
oneway void unregisterMediaButtonIntent(in PendingIntent pi, in ComponentName c);
107111

policy/src/com/android/internal/policy/impl/KeyguardViewBase.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@
2424
import android.graphics.PorterDuff;
2525
import android.graphics.drawable.Drawable;
2626
import android.media.AudioManager;
27+
import android.media.IAudioService;
28+
import android.os.RemoteException;
29+
import android.os.ServiceManager;
2730
import android.telephony.TelephonyManager;
2831
import android.view.KeyEvent;
2932
import android.view.View;
3033
import android.view.Gravity;
3134
import android.widget.FrameLayout;
3235
import android.util.AttributeSet;
36+
import android.util.Log;
37+
import android.util.Slog;
3338

3439
/**
3540
* Base class for keyguard views. {@link #reset} is where you should
@@ -194,9 +199,7 @@ private boolean interceptMediaKey(KeyEvent event) {
194199
case KeyEvent.KEYCODE_MEDIA_REWIND:
195200
case KeyEvent.KEYCODE_MEDIA_RECORD:
196201
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
197-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
198-
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
199-
getContext().sendOrderedBroadcast(intent, null);
202+
handleMediaKeyEvent(event);
200203
return true;
201204
}
202205

@@ -240,16 +243,28 @@ private boolean interceptMediaKey(KeyEvent event) {
240243
case KeyEvent.KEYCODE_MEDIA_REWIND:
241244
case KeyEvent.KEYCODE_MEDIA_RECORD:
242245
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
243-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
244-
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
245-
getContext().sendOrderedBroadcast(intent, null);
246+
handleMediaKeyEvent(event);
246247
return true;
247248
}
248249
}
249250
}
250251
return false;
251252
}
252253

254+
void handleMediaKeyEvent(KeyEvent keyEvent) {
255+
IAudioService audioService = IAudioService.Stub.asInterface(
256+
ServiceManager.checkService(Context.AUDIO_SERVICE));
257+
if (audioService != null) {
258+
try {
259+
audioService.dispatchMediaKeyEvent(keyEvent);
260+
} catch (RemoteException e) {
261+
Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
262+
}
263+
} else {
264+
Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
265+
}
266+
}
267+
253268
@Override
254269
public void dispatchSystemUiVisibilityChanged(int visibility) {
255270
super.dispatchSystemUiVisibilityChanged(visibility);

policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@
2323
import android.content.Intent;
2424
import android.content.res.Configuration;
2525
import android.media.AudioManager;
26+
import android.media.IAudioService;
27+
import android.os.RemoteException;
28+
import android.os.ServiceManager;
2629
import android.telephony.TelephonyManager;
2730
import android.util.EventLog;
31+
import android.util.Log;
2832
import android.util.Slog;
2933
import android.view.View;
3034
import android.view.HapticFeedbackConstants;
@@ -99,9 +103,7 @@ boolean onKeyDown(int keyCode, KeyEvent event) {
99103
case KeyEvent.KEYCODE_MEDIA_REWIND:
100104
case KeyEvent.KEYCODE_MEDIA_RECORD:
101105
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
102-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
103-
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
104-
mContext.sendOrderedBroadcast(intent, null);
106+
handleMediaKeyEvent(event);
105107
return true;
106108
}
107109

@@ -213,9 +215,7 @@ boolean onKeyUp(int keyCode, KeyEvent event) {
213215
case KeyEvent.KEYCODE_MEDIA_REWIND:
214216
case KeyEvent.KEYCODE_MEDIA_RECORD:
215217
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
216-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
217-
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
218-
mContext.sendOrderedBroadcast(intent, null);
218+
handleMediaKeyEvent(event);
219219
return true;
220220
}
221221

@@ -285,5 +285,19 @@ AudioManager getAudioManager() {
285285
void sendCloseSystemWindows() {
286286
PhoneWindowManager.sendCloseSystemWindows(mContext, null);
287287
}
288+
289+
private void handleMediaKeyEvent(KeyEvent keyEvent) {
290+
IAudioService audioService = IAudioService.Stub.asInterface(
291+
ServiceManager.checkService(Context.AUDIO_SERVICE));
292+
if (audioService != null) {
293+
try {
294+
audioService.dispatchMediaKeyEvent(keyEvent);
295+
} catch (RemoteException e) {
296+
Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
297+
}
298+
} else {
299+
Slog.w(TAG, "Unable to find IAudioService for media key event.");
300+
}
301+
}
288302
}
289303

policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,20 +3299,19 @@ class PassHeadsetKey implements Runnable {
32993299

33003300
public void run() {
33013301
if (ActivityManagerNative.isSystemReady()) {
3302-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3303-
intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
3304-
mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
3305-
mHandler, Activity.RESULT_OK, null, null);
3302+
IAudioService audioService = getAudioService();
3303+
if (audioService != null) {
3304+
try {
3305+
audioService.dispatchMediaKeyEventUnderWakelock(mKeyEvent);
3306+
} catch (RemoteException e) {
3307+
Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
3308+
}
3309+
}
3310+
mBroadcastWakeLock.release();
33063311
}
33073312
}
33083313
}
33093314

3310-
BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
3311-
public void onReceive(Context context, Intent intent) {
3312-
mBroadcastWakeLock.release();
3313-
}
3314-
};
3315-
33163315
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
33173316
public void onReceive(Context context, Intent intent) {
33183317
if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {

0 commit comments

Comments
 (0)