Skip to content

Commit f0cff04

Browse files
committed
Bug 5300223 RemoteControlClient uses PendingIntent for media button events
Update the implementation of the RemoteControlClient / Display feature rely on PendingIntent as provided in the construction of the RemoteControlClient instance. The ComponentName that describes the target of the media button events is set as the target of the Intent from which a PendingIntent is constructed. This ComponentName is still saved in the stack for persisting the last media button event receiver. This CL also updates the lockscreen IRemoteControlDisplay implementation to use the PendingIntent supplied by the application when sending transport control events. A (good) side effect of doing this is that intent will be directly targeted at the application. Restoration of the media button event receiver after reboot is not fully functional yet. Change-Id: I2be82f2839e9dee1de02512437b3fb41cc386cde
1 parent 34d0d30 commit f0cff04

6 files changed

Lines changed: 186 additions & 146 deletions

File tree

core/java/com/android/internal/widget/TransportControlView.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.android.internal.widget.LockScreenWidgetCallback;
2222
import com.android.internal.widget.LockScreenWidgetInterface;
2323

24+
import android.app.PendingIntent;
25+
import android.app.PendingIntent.CanceledException;
2426
import android.content.ComponentName;
2527
import android.content.Context;
2628
import android.content.Intent;
@@ -68,7 +70,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
6870
private int mClientGeneration;
6971
private Metadata mMetadata = new Metadata();
7072
private boolean mAttached;
71-
private ComponentName mClientName;
73+
private PendingIntent mClientIntent;
7274
private int mTransportControlFlags;
7375
private int mPlayState;
7476
private AudioManager mAudioManager;
@@ -116,7 +118,7 @@ public void handleMessage(Message msg) {
116118
}
117119
}
118120
mClientGeneration = msg.arg1;
119-
mClientName = (ComponentName) msg.obj;
121+
mClientIntent = (PendingIntent) msg.obj;
120122
break;
121123

122124
}
@@ -174,12 +176,12 @@ public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
174176
}
175177
}
176178

177-
public void setCurrentClientId(int clientGeneration, ComponentName clientEventReceiver,
179+
public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
178180
boolean clearing) throws RemoteException {
179181
Handler handler = mLocalHandler.get();
180182
if (handler != null) {
181183
handler.obtainMessage(MSG_SET_GENERATION_ID,
182-
clientGeneration, (clearing ? 1 : 0), clientEventReceiver).sendToTarget();
184+
clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
183185
}
184186
}
185187
};
@@ -365,16 +367,27 @@ public void onClick(View v) {
365367
}
366368

367369
private void sendMediaButtonClick(int keyCode) {
368-
// TODO: target to specific player based on mClientName
370+
// use the registered PendingIntent that will be processed by the registered
371+
// media button event receiver, which is the component of mClientIntent
369372
KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
370373
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
371374
intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
372-
getContext().sendOrderedBroadcast(intent, null);
375+
try {
376+
mClientIntent.send(getContext(), 0, intent);
377+
} catch (CanceledException e) {
378+
Log.e(TAG, "Error sending intent for media button down: "+e);
379+
e.printStackTrace();
380+
}
373381

374382
keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
375383
intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
376384
intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
377-
getContext().sendOrderedBroadcast(intent, null);
385+
try {
386+
mClientIntent.send(getContext(), 0, intent);
387+
} catch (CanceledException e) {
388+
Log.e(TAG, "Error sending intent for media button up: "+e);
389+
e.printStackTrace();
390+
}
378391
}
379392

380393
public void setCallback(LockScreenWidgetCallback callback) {

media/java/android/media/AudioManager.java

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
import android.annotation.SdkConstant;
2020
import android.annotation.SdkConstant.SdkConstantType;
21+
import android.app.PendingIntent;
2122
import android.content.ComponentName;
2223
import android.content.Context;
24+
import android.content.Intent;
2325
import android.database.ContentObserver;
2426
import android.graphics.Bitmap;
2527
import android.os.Binder;
@@ -1684,17 +1686,42 @@ public int abandonAudioFocus(OnAudioFocusChangeListener l) {
16841686
* Register a component to be the sole receiver of MEDIA_BUTTON intents.
16851687
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
16861688
* that will receive the media button intent. This broadcast receiver must be declared
1687-
* in the application manifest.
1689+
* in the application manifest. The package of the component must match that of
1690+
* the context you're registering from.
16881691
*/
16891692
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
16901693
if (eventReceiver == null) {
16911694
return;
16921695
}
1696+
if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
1697+
Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
1698+
"receiver and context package names don't match");
1699+
return;
1700+
}
1701+
// construct a PendingIntent for the media button and register it
1702+
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
1703+
// the associated intent will be handled by the component being registered
1704+
mediaButtonIntent.setComponent(eventReceiver);
1705+
PendingIntent pi = PendingIntent.getBroadcast(mContext,
1706+
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
1707+
registerMediaButtonIntent(pi, eventReceiver);
1708+
}
1709+
1710+
/**
1711+
* @hide
1712+
* no-op if (pi == null) or (eventReceiver == null)
1713+
*/
1714+
public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
1715+
if ((pi == null) || (eventReceiver == null)) {
1716+
Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
1717+
return;
1718+
}
16931719
IAudioService service = getService();
16941720
try {
1695-
service.registerMediaButtonEventReceiver(eventReceiver);
1721+
// pi != null
1722+
service.registerMediaButtonIntent(pi, eventReceiver);
16961723
} catch (RemoteException e) {
1697-
Log.e(TAG, "Dead object in registerMediaButtonEventReceiver"+e);
1724+
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
16981725
}
16991726
}
17001727

@@ -1707,15 +1734,27 @@ public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
17071734
if (eventReceiver == null) {
17081735
return;
17091736
}
1737+
// construct a PendingIntent for the media button and unregister it
1738+
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
1739+
// the associated intent will be handled by the component being registered
1740+
mediaButtonIntent.setComponent(eventReceiver);
1741+
PendingIntent pi = PendingIntent.getBroadcast(mContext,
1742+
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
1743+
unregisterMediaButtonIntent(pi, eventReceiver);
1744+
}
1745+
1746+
/**
1747+
* @hide
1748+
*/
1749+
public void unregisterMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
17101750
IAudioService service = getService();
17111751
try {
1712-
service.unregisterMediaButtonEventReceiver(eventReceiver);
1752+
service.unregisterMediaButtonIntent(pi, eventReceiver);
17131753
} catch (RemoteException e) {
1714-
Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiver"+e);
1754+
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
17151755
}
17161756
}
17171757

1718-
17191758
/**
17201759
* Registers the remote control client for providing information to display on the remote
17211760
* controls.
@@ -1724,14 +1763,13 @@ public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
17241763
* @see RemoteControlClient
17251764
*/
17261765
public void registerRemoteControlClient(RemoteControlClient rcClient) {
1727-
if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
1766+
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
17281767
return;
17291768
}
17301769
IAudioService service = getService();
17311770
try {
1732-
service.registerRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
1771+
service.registerRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */
17331772
rcClient.getIRemoteControlClient(), /* rcClient */
1734-
rcClient.toString(), /* clientName */
17351773
// used to match media button event receiver and audio focus
17361774
mContext.getPackageName()); /* packageName */
17371775
} catch (RemoteException e) {
@@ -1746,13 +1784,13 @@ public void registerRemoteControlClient(RemoteControlClient rcClient) {
17461784
* @see #registerRemoteControlClient(RemoteControlClient)
17471785
*/
17481786
public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
1749-
if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
1787+
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
17501788
return;
17511789
}
17521790
IAudioService service = getService();
17531791
try {
1754-
service.unregisterRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
1755-
rcClient.getIRemoteControlClient()); /* rcClient */
1792+
service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */
1793+
rcClient.getIRemoteControlClient()); /* rcClient */
17561794
} catch (RemoteException e) {
17571795
Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
17581796
}

0 commit comments

Comments
 (0)