Merge "Bug 5300223 RemoteControlClient uses PendingIntent for media button events" into ics-factoryrom

This commit is contained in:
Jean-Michel Trivi
2011-09-19 09:46:32 -07:00
committed by Android (Google) Code Review
6 changed files with 189 additions and 149 deletions

View File

@@ -21,6 +21,8 @@ import java.lang.ref.WeakReference;
import com.android.internal.widget.LockScreenWidgetCallback;
import com.android.internal.widget.LockScreenWidgetInterface;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -68,7 +70,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
private int mClientGeneration;
private Metadata mMetadata = new Metadata();
private boolean mAttached;
private ComponentName mClientName;
private PendingIntent mClientIntent;
private int mTransportControlFlags;
private int mPlayState;
private AudioManager mAudioManager;
@@ -116,7 +118,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
}
}
mClientGeneration = msg.arg1;
mClientName = (ComponentName) msg.obj;
mClientIntent = (PendingIntent) msg.obj;
break;
}
@@ -174,12 +176,12 @@ public class TransportControlView extends FrameLayout implements OnClickListener
}
}
public void setCurrentClientId(int clientGeneration, ComponentName clientEventReceiver,
public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
boolean clearing) throws RemoteException {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_GENERATION_ID,
clientGeneration, (clearing ? 1 : 0), clientEventReceiver).sendToTarget();
clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
}
}
};
@@ -365,16 +367,27 @@ public class TransportControlView extends FrameLayout implements OnClickListener
}
private void sendMediaButtonClick(int keyCode) {
// TODO: target to specific player based on mClientName
// use the registered PendingIntent that will be processed by the registered
// media button event receiver, which is the component of mClientIntent
KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
getContext().sendOrderedBroadcast(intent, null);
try {
mClientIntent.send(getContext(), 0, intent);
} catch (CanceledException e) {
Log.e(TAG, "Error sending intent for media button down: "+e);
e.printStackTrace();
}
keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
getContext().sendOrderedBroadcast(intent, null);
try {
mClientIntent.send(getContext(), 0, intent);
} catch (CanceledException e) {
Log.e(TAG, "Error sending intent for media button up: "+e);
e.printStackTrace();
}
}
public void setCallback(LockScreenWidgetCallback callback) {

View File

@@ -18,8 +18,10 @@ package android.media;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.os.Binder;
@@ -1684,17 +1686,42 @@ public class AudioManager {
* Register a component to be the sole receiver of MEDIA_BUTTON intents.
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
* that will receive the media button intent. This broadcast receiver must be declared
* in the application manifest.
* in the application manifest. The package of the component must match that of
* the context you're registering from.
*/
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
if (eventReceiver == null) {
return;
}
if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
"receiver and context package names don't match");
return;
}
// construct a PendingIntent for the media button and register it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
registerMediaButtonIntent(pi, eventReceiver);
}
/**
* @hide
* no-op if (pi == null) or (eventReceiver == null)
*/
public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
if ((pi == null) || (eventReceiver == null)) {
Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
return;
}
IAudioService service = getService();
try {
service.registerMediaButtonEventReceiver(eventReceiver);
// pi != null
service.registerMediaButtonIntent(pi, eventReceiver);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerMediaButtonEventReceiver"+e);
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
}
@@ -1707,14 +1734,26 @@ public class AudioManager {
if (eventReceiver == null) {
return;
}
IAudioService service = getService();
try {
service.unregisterMediaButtonEventReceiver(eventReceiver);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiver"+e);
}
// construct a PendingIntent for the media button and unregister it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
unregisterMediaButtonIntent(pi, eventReceiver);
}
/**
* @hide
*/
public void unregisterMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
IAudioService service = getService();
try {
service.unregisterMediaButtonIntent(pi, eventReceiver);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
}
}
/**
* Registers the remote control client for providing information to display on the remote
@@ -1724,14 +1763,13 @@ public class AudioManager {
* @see RemoteControlClient
*/
public void registerRemoteControlClient(RemoteControlClient rcClient) {
if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
return;
}
IAudioService service = getService();
try {
service.registerRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
service.registerRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */
rcClient.getIRemoteControlClient(), /* rcClient */
rcClient.toString(), /* clientName */
// used to match media button event receiver and audio focus
mContext.getPackageName()); /* packageName */
} catch (RemoteException e) {
@@ -1746,13 +1784,13 @@ public class AudioManager {
* @see #registerRemoteControlClient(RemoteControlClient)
*/
public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
return;
}
IAudioService service = getService();
try {
service.unregisterRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
rcClient.getIRemoteControlClient()); /* rcClient */
service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */
rcClient.getIRemoteControlClient()); /* rcClient */
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
}

View File

@@ -18,6 +18,8 @@ package android.media;
import android.app.ActivityManagerNative;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -35,6 +37,7 @@ import android.database.ContentObserver;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -2084,7 +2087,7 @@ public class AudioService extends IAudioService.Stub {
}
}
private void persistMediaButtonReceiver(ComponentName receiver) {
private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
receiver == null ? "" : receiver.flattenToString());
}
@@ -2201,7 +2204,7 @@ public class AudioService extends IAudioService.Stub {
break;
case MSG_PERSIST_MEDIABUTTONRECEIVER:
persistMediaButtonReceiver( (ComponentName) msg.obj );
onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
break;
case MSG_RCDISPLAY_CLEAR:
@@ -2894,14 +2897,22 @@ public class AudioService extends IAudioService.Stub {
}
synchronized(mRCStack) {
if (!mRCStack.empty()) {
// create a new intent specifically aimed at the current registered listener
// create a new intent to fill in the extras of the registered PendingIntent
Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
targetedIntent.putExtras(intent.getExtras());
targetedIntent.setComponent(mRCStack.peek().mReceiverComponent);
// trap the current broadcast
abortBroadcast();
//Log.v(TAG, " Sending intent" + targetedIntent);
context.sendBroadcast(targetedIntent, null);
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();
}
}
}
}
}
@@ -2936,18 +2947,18 @@ public class AudioService extends IAudioService.Stub {
*/
private class RcClientDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
private ComponentName mRcEventReceiver;
private PendingIntent mMediaIntent;
RcClientDeathHandler(IBinder cb, ComponentName eventReceiver) {
RcClientDeathHandler(IBinder cb, PendingIntent pi) {
mCb = cb;
mRcEventReceiver = eventReceiver;
mMediaIntent = pi;
}
public void binderDied() {
Log.w(TAG, " RemoteControlClient died");
// remote control client died, make sure the displays don't use it anymore
// by setting its remote control client to null
registerRemoteControlClient(mRcEventReceiver, null, null, null/*ignored*/);
registerRemoteControlClient(mMediaIntent, null, null/*ignored*/);
}
public IBinder getBinder() {
@@ -2956,18 +2967,29 @@ public class AudioService extends IAudioService.Stub {
}
private static class RemoteControlStackEntry {
/** the target for the ACTION_MEDIA_BUTTON events */
public ComponentName mReceiverComponent;// always non null
/**
* The target for the ACTION_MEDIA_BUTTON events.
* Always non null.
*/
public PendingIntent mMediaIntent;
/**
* The registered media button event receiver.
* Always non null.
*/
public ComponentName mReceiverComponent;
public String mCallingPackageName;
public String mRcClientName;
public int mCallingUid;
/** provides access to the information to display on the remote control */
/**
* Provides access to the information to display on the remote control.
* May be null (when a media button event receiver is registered,
* but no remote control client has been registered) */
public IRemoteControlClient mRcClient;
public RcClientDeathHandler mRcClientDeathHandler;
public RemoteControlStackEntry(ComponentName r) {
mReceiverComponent = r;
/** precondition: mediaIntent != null, eventReceiver != null */
public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
mMediaIntent = mediaIntent;
mReceiverComponent = eventReceiver;
mCallingUid = -1;
mRcClient = null;
}
@@ -3003,7 +3025,8 @@ public class AudioService extends IAudioService.Stub {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = stackIterator.next();
pw.println(" receiver: " + rcse.mReceiverComponent +
pw.println(" pi: " + rcse.mMediaIntent +
" -- ercvr: " + rcse.mReceiverComponent +
" -- client: " + rcse.mRcClient +
" -- uid: " + rcse.mCallingUid);
}
@@ -3035,7 +3058,6 @@ public class AudioService extends IAudioService.Stub {
mAudioHandler.sendMessage(
mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
null));
return;
} else if (oldTop != mRCStack.peek()) {
// the top of the stack has changed, save it in the system settings
// by posting a message to persist it
@@ -3049,25 +3071,32 @@ public class AudioService extends IAudioService.Stub {
/**
* Helper function:
* Restore remote control receiver from the system settings
* Restore remote control receiver from the system settings.
*/
private void restoreMediaButtonReceiver() {
String receiverName = Settings.System.getString(mContentResolver,
Settings.System.MEDIA_BUTTON_RECEIVER);
if ((null != receiverName) && !receiverName.isEmpty()) {
ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
registerMediaButtonEventReceiver(receiverComponentName);
ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
// construct a PendingIntent targeted to the restored component name
// for the media button and register it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
registerMediaButtonIntent(pi, eventReceiver);
}
// upon restoring (e.g. after boot), do we want to refresh all remotes?
}
/**
* Helper function:
* Set the new remote control receiver at the top of the RC focus stack
* Set the new remote control receiver at the top of the RC focus stack.
* precondition: mediaIntent != null, target != null
*/
private void pushMediaButtonReceiver(ComponentName newReceiver) {
private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) {
// already at top of stack?
if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) {
if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
return;
}
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
@@ -3075,31 +3104,32 @@ public class AudioService extends IAudioService.Stub {
boolean wasInsideStack = false;
while(stackIterator.hasNext()) {
rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
if(rcse.mMediaIntent.equals(mediaIntent)) {
wasInsideStack = true;
stackIterator.remove();
break;
}
}
if (!wasInsideStack) {
rcse = new RemoteControlStackEntry(newReceiver);
rcse = new RemoteControlStackEntry(mediaIntent, target);
}
mRCStack.push(rcse);
// post message to persist the default media button receiver
mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, newReceiver/*obj*/) );
MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
}
/**
* Helper function:
* Remove the remote control receiver from the RC focus stack
* Remove the remote control receiver from the RC focus stack.
* precondition: pi != null
*/
private void removeMediaButtonReceiver(ComponentName newReceiver) {
private void removeMediaButtonReceiver(PendingIntent pi) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
if(rcse.mMediaIntent.equals(pi)) {
stackIterator.remove();
break;
}
@@ -3110,8 +3140,8 @@ public class AudioService extends IAudioService.Stub {
* Helper function:
* Called synchronized on mRCStack
*/
private boolean isCurrentRcController(ComponentName eventReceiver) {
if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(eventReceiver)) {
private boolean isCurrentRcController(PendingIntent pi) {
if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
return true;
}
return false;
@@ -3124,12 +3154,12 @@ public class AudioService extends IAudioService.Stub {
* Update the remote control displays with the new "focused" client generation
*/
private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
ComponentName newClientEventReceiver, boolean clearing) {
PendingIntent newMediaIntent, boolean clearing) {
// NOTE: Only one IRemoteControlDisplay supported in this implementation
if (mRcDisplay != null) {
try {
mRcDisplay.setCurrentClientId(
newClientGeneration, newClientEventReceiver, clearing);
newClientGeneration, newMediaIntent, clearing);
} catch (RemoteException e) {
Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
// if we had a display before, stop monitoring its death
@@ -3167,10 +3197,9 @@ public class AudioService extends IAudioService.Stub {
* where the display should be cleared.
*/
private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
ComponentName newClientEventReceiver, boolean clearing) {
PendingIntent newMediaIntent, boolean clearing) {
// send the new valid client generation ID to all displays
setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newClientEventReceiver,
clearing);
setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
// send the new valid client generation ID to all clients
setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
}
@@ -3186,7 +3215,7 @@ public class AudioService extends IAudioService.Stub {
mCurrentRcClientGen++;
// synchronously update the displays and clients with the new client generation
setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
null /*event receiver*/, true /*clearing*/);
null /*newMediaIntent*/, true /*clearing*/);
}
}
}
@@ -3204,7 +3233,7 @@ public class AudioService extends IAudioService.Stub {
// synchronously update the displays and clients with
// the new client generation
setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
rcse.mReceiverComponent /*event receiver*/,
rcse.mMediaIntent /*newMediaIntent*/,
false /*clearing*/);
// tell the current client that it needs to send info
@@ -3301,27 +3330,34 @@ public class AudioService extends IAudioService.Stub {
updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
}
/** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver);
/**
* see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
* precondition: mediaIntent != null, target != null
*/
public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent);
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
pushMediaButtonReceiver(eventReceiver);
pushMediaButtonReceiver(mediaIntent, eventReceiver);
// new RC client, assume every type of information shall be queried
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
}
/** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver);
/**
* see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
* precondition: mediaIntent != null, eventReceiver != null
*/
public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
{
Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent);
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
boolean topOfStackWillChange = isCurrentRcController(eventReceiver);
removeMediaButtonReceiver(eventReceiver);
boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
removeMediaButtonReceiver(mediaIntent);
if (topOfStackWillChange) {
// current RC client will change, assume every type of info needs to be queried
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
@@ -3331,8 +3367,8 @@ public class AudioService extends IAudioService.Stub {
}
/** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
public void registerRemoteControlClient(ComponentName eventReceiver,
IRemoteControlClient rcClient, String clientName, String callingPackageName) {
public void registerRemoteControlClient(PendingIntent mediaIntent,
IRemoteControlClient rcClient, String callingPackageName) {
if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
@@ -3340,7 +3376,7 @@ public class AudioService extends IAudioService.Stub {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = stackIterator.next();
if(rcse.mReceiverComponent.equals(eventReceiver)) {
if(rcse.mMediaIntent.equals(mediaIntent)) {
// already had a remote control client?
if (rcse.mRcClientDeathHandler != null) {
// stop monitoring the old client's death
@@ -3357,7 +3393,6 @@ public class AudioService extends IAudioService.Stub {
}
}
rcse.mCallingPackageName = callingPackageName;
rcse.mRcClientName = clientName;
rcse.mCallingUid = Binder.getCallingUid();
if (rcClient == null) {
rcse.mRcClientDeathHandler = null;
@@ -3366,7 +3401,7 @@ public class AudioService extends IAudioService.Stub {
// monitor the new client's death
IBinder b = rcClient.asBinder();
RcClientDeathHandler rcdh =
new RcClientDeathHandler(b, rcse.mReceiverComponent);
new RcClientDeathHandler(b, rcse.mMediaIntent);
try {
b.linkToDeath(rcdh, 0);
} catch (RemoteException e) {
@@ -3380,7 +3415,7 @@ public class AudioService extends IAudioService.Stub {
}
// if the eventReceiver is at the top of the stack
// then check for potential refresh of the remote controls
if (isCurrentRcController(eventReceiver)) {
if (isCurrentRcController(mediaIntent)) {
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
}
}
@@ -3388,24 +3423,23 @@ public class AudioService extends IAudioService.Stub {
}
/**
* see AudioManager.unregisterRemoteControlClient(ComponentName eventReceiver, ...)
* see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
* rcClient is guaranteed non-null
*/
public void unregisterRemoteControlClient(ComponentName eventReceiver,
public void unregisterRemoteControlClient(PendingIntent mediaIntent,
IRemoteControlClient rcClient) {
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = stackIterator.next();
if ((rcse.mReceiverComponent.equals(eventReceiver))
if ((rcse.mMediaIntent.equals(mediaIntent))
&& rcClient.equals(rcse.mRcClient)) {
// we found the IRemoteControlClient to unregister
// stop monitoring its death
rcse.unlinkToRcClientDeath();
// reset the client-related fields
rcse.mRcClient = null;
rcse.mRcClientName = null;
rcse.mRcClientDeathHandler = null;
rcse.mCallingPackageName = null;
}

View File

@@ -16,6 +16,7 @@
package android.media;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.media.IAudioFocusDispatcher;
import android.media.IRemoteControlClient;
@@ -85,13 +86,12 @@ interface IAudioService {
void unregisterAudioFocusClient(String clientId);
void registerMediaButtonEventReceiver(in ComponentName eventReceiver);
oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
oneway void unregisterMediaButtonIntent(in PendingIntent pi, in ComponentName c);
void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
oneway void registerRemoteControlClient(in ComponentName eventReceiver,
in IRemoteControlClient rcClient, in String clientName, in String callingPackageName);
oneway void unregisterRemoteControlClient(in ComponentName eventReceiver,
oneway void registerRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient, in String callingPackageName);
oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient);
oneway void registerRemoteControlDisplay(in IRemoteControlDisplay rcd);

View File

@@ -16,6 +16,7 @@
package android.media;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -31,14 +32,12 @@ oneway interface IRemoteControlDisplay
/**
* Sets the generation counter of the current client that is displayed on the remote control.
* @param clientGeneration the new RemoteControlClient generation
* @param clientEventReceiver the media button event receiver associated with the client.
* May be null, which implies there is no registered media button event receiver. This
* parameter is supplied as an optimization so a display can directly target media button
* events to the client.
* @param clientMediaIntent the PendingIntent associated with the client.
* May be null, which implies there is no registered media button event receiver.
* @param clearing true if the new client generation value maps to a remote control update
* where the display should be cleared.
*/
void setCurrentClientId(int clientGeneration, in ComponentName clientEventReceiver,
void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent,
boolean clearing);
void setPlaybackState(int generationId, int state);

View File

@@ -34,6 +34,7 @@ import android.util.Log;
import java.lang.IllegalArgumentException;
/**
* TODO javadoc update for ComponentName - PendingIntent change
* RemoteControlClient enables exposing information meant to be consumed by remote controls
* capable of displaying metadata, artwork and media transport control buttons.
* A remote control client object is associated with a media button event receiver. This
@@ -204,50 +205,6 @@ public class RemoteControlClient
*/
public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
/**
* @hide
* TODO remove after modifying known (internal) media apps using this API
* Class constructor.
* @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
* been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
* before this new RemoteControlClient can itself be registered with
* {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
* @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
public RemoteControlClient(ComponentName mediaButtonEventReceiver) {
mRcEventReceiver = mediaButtonEventReceiver;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
}
}
/**
* @hide
* TODO remove after modifying known (internal) media apps using this API
* Class constructor for a remote control client whose internal event handling
* happens on a user-provided Looper.
* @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
* been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
* before this new RemoteControlClient can itself be registered with
* {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
* @param looper The Looper running the event loop.
* @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
public RemoteControlClient(ComponentName mediaButtonEventReceiver, Looper looper) {
mRcEventReceiver = mediaButtonEventReceiver;
mEventHandler = new EventHandler(this, looper);
}
/**
* Class constructor.
* @param mediaButtonIntent The intent that will be sent for the media button events sent
@@ -262,8 +219,7 @@ public class RemoteControlClient
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
public RemoteControlClient(PendingIntent mediaButtonIntent) {
// TODO implement using PendingIntent instead of ComponentName
mRcEventReceiver = null;
mRcMediaIntent = mediaButtonIntent;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -292,8 +248,7 @@ public class RemoteControlClient
* @see AudioManager#registerRemoteControlClient(RemoteControlClient)
*/
public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
// TODO implement using PendingIntent instead of ComponentName
mRcEventReceiver = null;
mRcMediaIntent = mediaButtonIntent;
mEventHandler = new EventHandler(this, looper);
}
@@ -614,9 +569,10 @@ public class RemoteControlClient
private int mInternalClientGenId = -2;
/**
* The media button event receiver associated with this remote control client
* The media button intent description associated with this remote control client
* (can / should include target component for intent handling)
*/
private final ComponentName mRcEventReceiver;
private final PendingIntent mRcMediaIntent;
/**
* The remote control display to which this client will send information.
@@ -626,10 +582,10 @@ public class RemoteControlClient
/**
* @hide
* Accessor to media button event receiver
* Accessor to media button intent description (includes target component)
*/
public ComponentName getRcEventReceiver() {
return mRcEventReceiver;
public PendingIntent getRcMediaIntent() {
return mRcMediaIntent;
}
/**
* @hide