diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f279e636bec7e..875bc8f18357b 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2006,6 +2006,37 @@ public class AudioManager { } } + /** + * @hide + * Used internally by telephony package to register an intent receiver for ACTION_MEDIA_BUTTON. + * @param eventReceiver the component that will receive the media button key events, + * no-op if eventReceiver is null + */ + public void registerMediaButtonEventReceiverForCalls(ComponentName eventReceiver) { + if (eventReceiver == null) { + return; + } + IAudioService service = getService(); + try { + // eventReceiver != null + service.registerMediaButtonEventReceiverForCalls(eventReceiver); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in registerMediaButtonEventReceiverForCalls", e); + } + } + + /** + * @hide + */ + public void unregisterMediaButtonEventReceiverForCalls() { + IAudioService service = getService(); + try { + service.unregisterMediaButtonEventReceiverForCalls(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiverForCalls", e); + } + } + /** * Unregister the receiver of MEDIA_BUTTON intents. * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 8da7d0fb89664..d165b5e7cfd64 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -3625,12 +3625,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { Log.e(TAG, "not dispatching invalid media key event " + keyEvent); return; } - // event filtering based on audio mode + // event filtering for telephony synchronized(mRingingLock) { - if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) || - (getMode() == AudioSystem.MODE_IN_COMMUNICATION) || - (getMode() == AudioSystem.MODE_RINGTONE) ) { - return; + synchronized(mRCStack) { + if ((mMediaReceiverForCalls != null) && + (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) { + dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); + return; + } } } // event filtering based on voice-based interactions @@ -3641,6 +3643,25 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + /** + * Handles the dispatching of the media button events to the telephony package. + * Precondition: mMediaReceiverForCalls != null + * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons + * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event + * is dispatched. + */ + private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); + } + mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, + mAudioHandler, Activity.RESULT_OK, null, null); + } + /** * Handles the dispatching of the media button events to one of the registered listeners, * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. @@ -4027,6 +4048,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished { */ private final Stack mRCStack = new Stack(); + /** + * The component the telephony package can register so telephony calls have priority to + * handle media button events + */ + private ComponentName mMediaReceiverForCalls = null; + /** * Helper function: * Display in the log the current entries in the remote control focus stack @@ -4380,6 +4407,35 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + /** + * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) + * precondition: c != null + */ + public void registerMediaButtonEventReceiverForCalls(ComponentName c) { + if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") + != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Invalid permissions to register media button receiver for calls"); + return; + } + synchronized(mRCStack) { + mMediaReceiverForCalls = c; + } + } + + /** + * see AudioManager.unregisterMediaButtonEventReceiverForCalls() + */ + public void unregisterMediaButtonEventReceiverForCalls() { + if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") + != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); + return; + } + synchronized(mRCStack) { + mMediaReceiverForCalls = null; + } + } + /** * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 48f091c796e66..6753ad37a3776 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -109,6 +109,9 @@ interface IAudioService { oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c); oneway void unregisterMediaButtonIntent(in PendingIntent pi, in ComponentName c); + oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c); + oneway void unregisterMediaButtonEventReceiverForCalls(); + oneway void registerRemoteControlClient(in PendingIntent mediaIntent, in IRemoteControlClient rcClient, in String callingPackageName); oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,