Skip to content

Commit 8ccfbdd

Browse files
jmtriviAndroid (Google) Code Review
authored andcommitted
Merge "Optimize how AudioService receives media button events" into jb-dev
2 parents 6dbac37 + c680222 commit 8ccfbdd

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
@@ -3343,20 +3343,19 @@ class PassHeadsetKey implements Runnable {
33433343

33443344
public void run() {
33453345
if (ActivityManagerNative.isSystemReady()) {
3346-
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3347-
intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
3348-
mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
3349-
mHandler, Activity.RESULT_OK, null, null);
3346+
IAudioService audioService = getAudioService();
3347+
if (audioService != null) {
3348+
try {
3349+
audioService.dispatchMediaKeyEventUnderWakelock(mKeyEvent);
3350+
} catch (RemoteException e) {
3351+
Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
3352+
}
3353+
}
3354+
mBroadcastWakeLock.release();
33503355
}
33513356
}
33523357
}
33533358

3354-
BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
3355-
public void onReceive(Context context, Intent intent) {
3356-
mBroadcastWakeLock.release();
3357-
}
3358-
};
3359-
33603359
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
33613360
public void onReceive(Context context, Intent intent) {
33623361
if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {

0 commit comments

Comments
 (0)