Merge "Bug 5300223 RemoteControlClient uses PendingIntent for media button events" into ics-factoryrom
This commit is contained in:
committed by
Android (Google) Code Review
commit
2f15316959
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user