Merge "Optimize how AudioService receives media button events" into jb-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
8ccfbdddab
@@ -21,10 +21,12 @@ import static android.media.AudioManager.RINGER_MODE_NORMAL;
|
||||
import static android.media.AudioManager.RINGER_MODE_SILENT;
|
||||
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.PendingIntent.CanceledException;
|
||||
import android.app.PendingIntent.OnFinished;
|
||||
import android.bluetooth.BluetoothA2dp;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
@@ -48,6 +50,7 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
@@ -85,7 +88,7 @@ import java.util.Stack;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class AudioService extends IAudioService.Stub {
|
||||
public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
|
||||
private static final String TAG = "AudioService";
|
||||
|
||||
@@ -289,10 +292,6 @@ public class AudioService extends IAudioService.Stub {
|
||||
// Broadcast receiver for device connections intent broadcasts
|
||||
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
|
||||
|
||||
// Broadcast receiver for media button broadcasts (separate from mReceiver to
|
||||
// independently change its priority)
|
||||
private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
|
||||
|
||||
// Used to alter media button redirection when the phone is ringing.
|
||||
private boolean mIsRinging = false;
|
||||
|
||||
@@ -383,6 +382,9 @@ public class AudioService extends IAudioService.Stub {
|
||||
mVoiceCapable = mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_voice_capable);
|
||||
|
||||
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
||||
mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mediaKeyEvent");
|
||||
|
||||
// Intialized volume
|
||||
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
|
||||
"ro.config.vc_call_vol_steps",
|
||||
@@ -434,13 +436,6 @@ public class AudioService extends IAudioService.Stub {
|
||||
pkgFilter.addDataScheme("package");
|
||||
context.registerReceiver(mReceiver, pkgFilter);
|
||||
|
||||
// Register for media button intent broadcasts.
|
||||
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
|
||||
// Workaround for bug on priority setting
|
||||
//intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
|
||||
intentFilter.setPriority(Integer.MAX_VALUE);
|
||||
context.registerReceiver(mMediaButtonReceiver, intentFilter);
|
||||
|
||||
// Register for phone state monitoring
|
||||
TelephonyManager tmgr = (TelephonyManager)
|
||||
context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
@@ -3492,54 +3487,109 @@ public class AudioService extends IAudioService.Stub {
|
||||
//==========================================================================================
|
||||
// RemoteControl
|
||||
//==========================================================================================
|
||||
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
|
||||
dispatchMediaKeyEvent(keyEvent, false /*needWakeLock*/);
|
||||
}
|
||||
|
||||
public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
|
||||
dispatchMediaKeyEvent(keyEvent, true /*needWakeLock*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receiver for media button intents. Handles the dispatching of the media button event
|
||||
* to one of the registered listeners, or if there was none, resumes the intent broadcast
|
||||
* to the rest of the system.
|
||||
* Handles the dispatching of the media button events to one of the registered listeners,
|
||||
* or if there was none, broadcast a ACTION_MEDIA_BUTTON intent to the rest of the system.
|
||||
*/
|
||||
private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) {
|
||||
private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
|
||||
// sanity check on the incoming key event
|
||||
if (!isValidMediaKeyEvent(keyEvent)) {
|
||||
Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
|
||||
return;
|
||||
}
|
||||
// event filtering
|
||||
synchronized(mRingingLock) {
|
||||
if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
|
||||
(getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
|
||||
(getMode() == AudioSystem.MODE_RINGTONE) ) {
|
||||
return;
|
||||
}
|
||||
KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||
if (event != null) {
|
||||
// if in a call or ringing, do not break the current phone app behavior
|
||||
// TODO modify this to let the phone app specifically get the RC focus
|
||||
// add modify the phone app to take advantage of the new API
|
||||
synchronized(mRingingLock) {
|
||||
if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) ||
|
||||
(getMode() == AudioSystem.MODE_IN_COMMUNICATION) ||
|
||||
(getMode() == AudioSystem.MODE_RINGTONE) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (needWakeLock) {
|
||||
mMediaEventWakeLock.acquire();
|
||||
}
|
||||
Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
|
||||
synchronized(mRCStack) {
|
||||
if (!mRCStack.empty()) {
|
||||
// send the intent that was registered by the client
|
||||
try {
|
||||
mRCStack.peek().mMediaIntent.send(mContext,
|
||||
needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
|
||||
keyIntent, AudioService.this, mAudioHandler);
|
||||
} catch (CanceledException e) {
|
||||
Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
|
||||
e.printStackTrace();
|
||||
}
|
||||
synchronized(mRCStack) {
|
||||
if (!mRCStack.empty()) {
|
||||
// create a new intent to fill in the extras of the registered PendingIntent
|
||||
Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
targetedIntent.putExtras(extras);
|
||||
// trap the current broadcast
|
||||
abortBroadcast();
|
||||
//Log.v(TAG, " Sending intent" + targetedIntent);
|
||||
// send the intent that was registered by the client
|
||||
try {
|
||||
mRCStack.peek().mMediaIntent.send(context, 0, targetedIntent);
|
||||
} catch (CanceledException e) {
|
||||
Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// legacy behavior when nobody registered their media button event receiver
|
||||
// through AudioManager
|
||||
if (needWakeLock) {
|
||||
keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
|
||||
}
|
||||
mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
|
||||
mAudioHandler, Activity.RESULT_OK, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
|
||||
if (keyEvent == null) {
|
||||
return false;
|
||||
}
|
||||
final int keyCode = keyEvent.getKeyCode();
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_CLOSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_EJECT:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private PowerManager.WakeLock mMediaEventWakeLock;
|
||||
|
||||
private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
|
||||
|
||||
// only set when wakelock was acquired, no need to check value when received
|
||||
private static final String EXTRA_WAKELOCK_ACQUIRED =
|
||||
"android.media.AudioService.WAKELOCK_ACQUIRED";
|
||||
|
||||
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
|
||||
int resultCode, String resultData, Bundle resultExtras) {
|
||||
if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
|
||||
mMediaEventWakeLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getExtras().containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
|
||||
mMediaEventWakeLock.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Object mCurrentRcLock = new Object();
|
||||
/**
|
||||
* The one remote control client which will receive a request for display information.
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.media.IRemoteControlClient;
|
||||
import android.media.IRemoteControlDisplay;
|
||||
import android.media.IRingtonePlayer;
|
||||
import android.net.Uri;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@@ -102,6 +103,9 @@ interface IAudioService {
|
||||
|
||||
void unregisterAudioFocusClient(String clientId);
|
||||
|
||||
oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
|
||||
void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
|
||||
|
||||
oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
|
||||
oneway void unregisterMediaButtonIntent(in PendingIntent pi, in ComponentName c);
|
||||
|
||||
|
||||
@@ -24,12 +24,17 @@ import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IAudioService;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Gravity;
|
||||
import android.widget.FrameLayout;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* Base class for keyguard views. {@link #reset} is where you should
|
||||
@@ -194,9 +199,7 @@ public abstract class KeyguardViewBase extends FrameLayout {
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
getContext().sendOrderedBroadcast(intent, null);
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -240,9 +243,7 @@ public abstract class KeyguardViewBase extends FrameLayout {
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
getContext().sendOrderedBroadcast(intent, null);
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -250,6 +251,20 @@ public abstract class KeyguardViewBase extends FrameLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
void handleMediaKeyEvent(KeyEvent keyEvent) {
|
||||
IAudioService audioService = IAudioService.Stub.asInterface(
|
||||
ServiceManager.checkService(Context.AUDIO_SERVICE));
|
||||
if (audioService != null) {
|
||||
try {
|
||||
audioService.dispatchMediaKeyEvent(keyEvent);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
|
||||
}
|
||||
} else {
|
||||
Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchSystemUiVisibilityChanged(int visibility) {
|
||||
super.dispatchSystemUiVisibilityChanged(visibility);
|
||||
|
||||
@@ -23,8 +23,12 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IAudioService;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
@@ -99,9 +103,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
mContext.sendOrderedBroadcast(intent, null);
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -213,9 +215,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
mContext.sendOrderedBroadcast(intent, null);
|
||||
handleMediaKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -285,5 +285,19 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
||||
void sendCloseSystemWindows() {
|
||||
PhoneWindowManager.sendCloseSystemWindows(mContext, null);
|
||||
}
|
||||
|
||||
private void handleMediaKeyEvent(KeyEvent keyEvent) {
|
||||
IAudioService audioService = IAudioService.Stub.asInterface(
|
||||
ServiceManager.checkService(Context.AUDIO_SERVICE));
|
||||
if (audioService != null) {
|
||||
try {
|
||||
audioService.dispatchMediaKeyEvent(keyEvent);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "Unable to find IAudioService for media key event.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3343,20 +3343,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
|
||||
public void run() {
|
||||
if (ActivityManagerNative.isSystemReady()) {
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
|
||||
mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
|
||||
mHandler, Activity.RESULT_OK, null, null);
|
||||
IAudioService audioService = getAudioService();
|
||||
if (audioService != null) {
|
||||
try {
|
||||
audioService.dispatchMediaKeyEventUnderWakelock(mKeyEvent);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
|
||||
}
|
||||
}
|
||||
mBroadcastWakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mBroadcastWakeLock.release();
|
||||
}
|
||||
};
|
||||
|
||||
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
|
||||
|
||||
Reference in New Issue
Block a user