我开发的音乐播放器。我有两个家,锁屏,工程一个小部件。我不想让用户从锁屏放置或删除插件的选项。
我的目标是:
小部件自动显示在主机锁屏上,取出小部件,有作为的时间,日期窗口小部件,或将在其。
管理MusicService和Widget一致。 (清除锁屏小工具,当我离开音乐播放器。 这是谷歌究竟是如何播放音乐小工具在我的Galaxy Nexus的(或许多其他手机)。这可能吗?难道我需要的东西,这不是一个小部件,如自定义锁屏?
解决方案好了,解决的办法很简单,不使用任何插件,只需使用的 RemoteControlClientCompat 类。这是我的lockScreenControls()方法,code,我打电话时,我想表明这种类型的控制。
私人无效lockScreenControls(){
//使用媒体按钮的API(如果有的话)来注册自己的媒体按钮
//事件
MediaButtonHelper.registerMediaButtonEventReceiverCompat(mAudioManager,mMediaButtonReceiverComponent);
//使用遥控器的API(如果可用)设置播放状态
如果(mRemoteControlClientCompat == NULL){
意向意图=新的意图(Intent.ACTION_MEDIA_BUTTON);
intent.setComponent(mMediaButtonReceiverComponent);
mRemoteControlClientCompat =新RemoteControlClientCompat(PendingIntent.getBroadcast(本/ *中* / 0 / *请求code,忽略 /,意图/ *意图* / 0 / *标志* /));
RemoteControlHelper.registerRemoteControlClient(mAudioManager,mRemoteControlClientCompat);
}
mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
mRemoteControlClientCompat.setTransportControlFlags(
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_ preVIOUS |
RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
RemoteControlClient.FLAG_KEY_MEDIA_STOP);
//更新遥控器
mRemoteControlClientCompat.editMetadata(真)
.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,NombreArtista)
.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,TITULO专辑)
.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,nombreCancion)
//。putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,playingItem.getDuration())
// TODO:提取实物艺术品
.putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK,getAlbumArt())
。应用();
}
}
*********** EDIT ************
RemoteControlClientCompat类:
@燮pressWarnings({rawtypes,未})
公共类RemoteControlClientCompat {
私有静态最后字符串变量=RemoteControlCompat;
私有静态类sRemoteControlClientClass;
// RCC简称RemoteControlClient
私有静态方法sRCCEditMetadataMethod;
私有静态方法sRCCSetPlayStateMethod;
私有静态方法sRCCSetTransportControlFlags;
私有静态布尔sHasRemoteControlAPIs = FALSE;
静态{
尝试 {
类加载器的类加载器= RemoteControlClientCompat.class.getClassLoader();
sRemoteControlClientClass = getActualRemoteControlClientClass器(classloader);
//动态填充playstate和标志值的情况下,他们改变
//在将来的版本。
对于(场场:RemoteControlClientCompat.class.getFields()){
尝试 {
字段realField = sRemoteControlClientClass.getField(field.getName());
对象realValue = realField.get(空);
field.set(NULL,realValue);
}赶上(NoSuchFieldException E){
Log.w(TAG,无法获得真正的现场:+ field.getName());
}赶上(抛出:IllegalArgumentException E){
Log.w(TAG,错误试图拉字段值:+ field.getName()
++ e.getMessage());
}赶上(IllegalAccessException E){
Log.w(TAG,错误试图拉字段值:+ field.getName()
++ e.getMessage());
}
}
//得到RemoteControlClient所需要的公共方法
sRCCEditMetadataMethod = sRemoteControlClientClass.getMethod(editMetadata
boolean.class);
sRCCSetPlayStateMethod = sRemoteControlClientClass.getMethod(setPlaybackState
int.class);
sRCCSetTransportControlFlags = sRemoteControlClientClass.getMethod(
setTransportControlFlags,int.class);
sHasRemoteControlAPIs = TRUE;
}赶上(ClassNotFoundException异常E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(NoSuchMethodException E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(抛出:IllegalArgumentException E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(SecurityException异常E){
ICS之前的操作系统上运行时,//静默失败。
}
}
公共静态类getActualRemoteControlClientClass(类加载器的类加载器)
抛出ClassNotFoundException的{
返回classLoader.loadClass(android.media.RemoteControlClient);
}
私有对象mActualRemoteControlClient;
公共RemoteControlClientCompat(PendingIntent pendingIntent){
如果(!sHasRemoteControlAPIs){
返回;
}
尝试 {
mActualRemoteControlClient =
sRemoteControlClientClass.getConstructor(PendingIntent.class)
.newInstance(pendingIntent);
}赶上(例外五){
抛出新的RuntimeException(E);
}
}
公共RemoteControlClientCompat(PendingIntent pendingIntent,活套活套){
如果(!sHasRemoteControlAPIs){
返回;
}
尝试 {
mActualRemoteControlClient =
sRemoteControlClientClass.getConstructor(PendingIntent.class,Looper.class)
.newInstance(pendingIntent,活套);
}赶上(例外五){
Log.e(TAG,错误创建新实例+ sRemoteControlClientClass.getName(),E);
}
}
/ **
*用于修改元数据在{@link android.media.RemoteControlClient}对象类。使用
* {@link android.media.RemoteControlClient#editMetadata(布尔)}创建一个实例
*编辑器,在其上设置的元数据RemoteControlClient实例。一旦所有的
*信息设置,使用{@link #apply()},使之成为新的元数据,应该是
*显示为相关客户端。一旦元数据被应用,你不能重用
*在MetadataEditor的这个实例。
* /
公共类MetadataEditorCompat {
私有方法mPutStringMethod;
私有方法mPutBitmapMethod;
私有方法mPutLongMethod;
私有方法mClearMethod;
私有方法mApplyMethod;
私有对象mActualMetadataEditor;
/ **
*元数据密钥内容的插图/专辑封面。
* /
公共最后静态INT METADATA_KEY_ARTWORK = 100;
私人MetadataEditorCompat(对象actualMetadataEditor){
如果(sHasRemoteControlAPIs&安培;&安培; actualMetadataEditor == NULL){
抛出新抛出:IllegalArgumentException(遥控器API的存在,+
不应该给空MetadataEditor);
}
如果(sHasRemoteControlAPIs){
类metadataEditorClass = actualMetadataEditor.getClass();
尝试 {
mPutStringMethod = metadataEditorClass.getMethod(putString
int.class,为String.class);
mPutBitmapMethod = metadataEditorClass.getMethod(putBitmap
int.class,Bitmap.class);
mPutLongMethod = metadataEditorClass.getMethod(putLong
int.class,long.class);
mClearMethod = metadataEditorClass.getMethod(清,新的等级[] {});
mApplyMethod = metadataEditorClass.getMethod(应用,新的等级[] {});
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
mActualMetadataEditor = actualMetadataEditor;
}
/ **
*添加到要显示的文本信息。
*请注意,没有经过{@link #apply()}被称为添加的信息,
*将显示。
* @参数密钥的所述元数据字段的标识符来设置。有效值
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}。
*参数值的文本给定键,或{@ code空}以表示没有有效
*信息领域。
* @返回返回引用同一个MetadataEditor对象,这样你就可以链认沽
*调用起来。
* /
公共MetadataEditorCompat putString(INT键,字符串值){
如果(sHasRemoteControlAPIs){
尝试 {
mPutStringMethod.invoke(mActualMetadataEditor,键,值);
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
回到这一点;
}
/ **
*设置相册/艺术品图片被遥控器上的显示。
* @参数关键位图的标识符来设置。唯一有效的值是
* {@link #METADATA_KEY_ARTWORK}
*参数位图中的位图作品,或NULL,如果没有任何。
* @返回返回引用同一个MetadataEditor对象,这样你就可以链认沽
*调用起来。
* @throws抛出:IllegalArgumentException
* @see android.graphics.Bitmap
* /
公共MetadataEditorCompat putBitmap(INT键,位图位图){
如果(sHasRemoteControlAPIs){
尝试 {
mPutBitmapMethod.invoke(mActualMetadataEditor,钥匙,位图);
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
回到这一点;
}
/ **
*增加了显示数字信息。
*请注意,没有经过{@link #apply()}被称为添加的信息,
*将显示。
* @参数密钥的所述元数据字段的标识符来设置。有效值
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION}(其值
* pssed以毫秒为单位EX $ P $)
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}。
*参数值给定键长值
* @返回返回引用同一个MetadataEditor对象,这样你就可以链认沽
*调用起来。
* @throws抛出:IllegalArgumentException
* /
公共MetadataEditorCompat putLong(INT键,长值){
如果(sHasRemoteControlAPIs){
尝试 {
mPutLongMethod.invoke(mActualMetadataEditor,键,值);
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
回到这一点;
}
/ **
*清除所有已设置自MetadataEditor实例是元数据
*与创建{@link android.media.RemoteControlClient#editMetadata(布尔)}。
* /
公共无效清除(){
如果(sHasRemoteControlAPIs){
尝试 {
mClearMethod.invoke(mActualMetadataEditor,(对象[])NULL);
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
}
/ **
* Associates均已经设置自MetadataEditor实例是元数据
*用{@link android.media.RemoteControlClient#editMetadata(布尔)},或自创建以来
* {@link #clear()}是所谓的,与RemoteControlClient。一旦申请,这
* MetadataEditor不能重复使用编辑RemoteControlClient的元数据。
* /
公共无效申请(){
如果(sHasRemoteControlAPIs){
尝试 {
mApplyMethod.invoke(mActualMetadataEditor,(对象[])NULL);
}赶上(例外五){
抛出新的RuntimeException(e.getMessage(),E);
}
}
}
}
/ **
*创建{@link android.media.RemoteControlClient.MetadataEditor}。
* @参数startEmpty设置为false,如果你想MetadataEditor包含的元数据
*为previously施加到RemoteControlClient,或真,如果它是要创建空的。
返回:一个新的MetadataEditor实例。
* /
公共MetadataEditorCompat editMetadata(布尔startEmpty){
对象metadataEditor;
如果(sHasRemoteControlAPIs){
尝试 {
metadataEditor = sRCCEditMetadataMethod.invoke(mActualRemoteControlClient,
startEmpty);
}赶上(例外五){
抛出新的RuntimeException(E);
}
} 其他 {
metadataEditor = NULL;
}
返回新MetadataEditorCompat(metadataEditor);
}
/ **
*设置当前的播放状态。
*参数状态当前的播放状态,下列值之一:
* {@link android.media.RemoteControlClient#PLAYSTATE_STOPPED},
* {@link android.media.RemoteControlClient#PLAYSTATE_PAUSED},
* {@link android.media.RemoteControlClient#PLAYSTATE_PLAYING},
* {@link android.media.RemoteControlClient#PLAYSTATE_FAST_FORWARDING},
* {@link android.media.RemoteControlClient#PLAYSTATE_REWINDING},
* {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_FORWARDS},
* {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_BACKWARDS},
* {@link android.media.RemoteControlClient#PLAYSTATE_BUFFERING},
* {@link android.media.RemoteControlClient#PLAYSTATE_ERROR}。
* /
公共无效setPlaybackState(INT状态){
如果(sHasRemoteControlAPIs){
尝试 {
sRCCSetPlayStateMethod.invoke(mActualRemoteControlClient,状态);
}赶上(例外五){
抛出新的RuntimeException(E);
}
}
}
/ **
*设置标志该客户端支持媒体传输控制按钮。
* @参数transportControlFlags下列标志的组合:
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_ preVIOUS},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT}
* /
公共无效setTransportControlFlags(INT transportControlFlags){
如果(sHasRemoteControlAPIs){
尝试 {
sRCCSetTransportControlFlags.invoke(mActualRemoteControlClient,
transportControlFlags);
}赶上(例外五){
抛出新的RuntimeException(E);
}
}
}
公共终对象getActualRemoteControlClientObject(){
返回mActualRemoteControlClient;
}
}
RemoteControlHelper类:
公共类RemoteControlHelper {
私有静态最后字符串变量=RemoteControlHelper;
私有静态布尔sHasRemoteControlAPIs = FALSE;
私有静态方法sRegisterRemoteControlClientMethod;
私有静态方法sUnregisterRemoteControlClientMethod;
静态{
尝试 {
类加载器的类加载器= RemoteControlHelper.class.getClassLoader();
类sRemoteControlClientClass =
RemoteControlClientCompat.getActualRemoteControlClientClass器(classloader);
sRegisterRemoteControlClientMethod = AudioManager.class.getMethod(
registerRemoteControlClient,新的等级[] {sRemoteControlClientClass});
sUnregisterRemoteControlClientMethod = AudioManager.class.getMethod(
unregisterRemoteControlClient,新的等级[] {sRemoteControlClientClass});
sHasRemoteControlAPIs = TRUE;
}赶上(ClassNotFoundException异常E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(NoSuchMethodException E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(抛出:IllegalArgumentException E){
ICS之前的操作系统上运行时,//静默失败。
}赶上(SecurityException异常E){
ICS之前的操作系统上运行时,//静默失败。
}
}
公共静态无效registerRemoteControlClient(AudioManager audioManager,
RemoteControlClientCompat remoteControlClient){
如果(!sHasRemoteControlAPIs){
返回;
}
尝试 {
sRegisterRemoteControlClientMethod.invoke(audioManager,
remoteControlClient.getActualRemoteControlClientObject());
}赶上(例外五){
Log.e(TAG,e.getMessage(),E);
}
}
公共静态无效unregisterRemoteControlClient(AudioManager audioManager,
RemoteControlClientCompat remoteControlClient){
如果(!sHasRemoteControlAPIs){
返回;
}
尝试 {
sUnregisterRemoteControlClientMethod.invoke(audioManager,
remoteControlClient.getActualRemoteControlClientObject());
}赶上(例外五){
Log.e(TAG,e.getMessage(),E);
}
}
}
要更改lockPlayer国家dinamicaly:
私人无效lockontrolsPlay(){
如果(mRemoteControlClientCompat!= NULL){
mRemoteControlClientCompat
.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
}
}
私人无效lockontrolsPause(){
如果(mRemoteControlClientCompat!= NULL){
mRemoteControlClientCompat
.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
}
}
接收器:
公共类MusicIntentReceiver扩展WakefulBroadcastReceiver {
私人诠释headsetSwitch = 1;
@覆盖
公共无效的onReceive(上下文的背景下,意图意图){
如果(intent.getAction()。等于(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)){
Toast.makeText(上下文,MyApplication.getContext()getResources()的getString(R.string.aptxt15),Toast.LENGTH_SHORT。).show();
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,pause_cascos);
context.startService(意向);
}否则,如果(intent.getAction()。等于(Intent.ACTION_MEDIA_BUTTON)){
的KeyEvent的keyEvent =(KeyEvent的)intent.getExtras()得到(Intent.EXTRA_KEY_EVENT)。
如果(keyEvent.getAction()!= KeyEvent.ACTION_DOWN)
返回;
开关(keyEvent.getKey code()){
案例KeyEvent.KEY code_HEADSETHOOK:
案例KeyEvent.KEY code_MEDIA_PLAY_PAUSE:
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,暂停);
context.startService(意向);
// context.startService(新意图(MusicService.ACTION_TOGGLE_PLAYBACK));
打破;
案例KeyEvent.KEY code_MEDIA_PLAY:
// context.startService(新意图(MusicService.ACTION_PLAY));
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,暂停);
context.startService(意向);
打破;
案例KeyEvent.KEY code_MEDIA_PAUSE:
// context.startService(新意图(MusicService.ACTION_PAUSE));
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,暂停);
context.startService(意向);
打破;
案例KeyEvent.KEY code_MEDIA_STOP:
// context.startService(新意图(MusicService.ACTION_STOP));
打破;
案例KeyEvent.KEY code_MEDIA_NEXT:
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,下一步);
context.startService(意向);
打破;
案例KeyEvent.KEY code_MEDIA_ preVIOUS:
// TODO:确保在快速连续这样做实际上扮演
// previous歌曲
// context.startService(新意图(MusicService.ACTION_REWIND));
意图=新的意图(背景下,ReproductorDialog.ServicioCanciones.class);
intent.putExtra(do_action,previous);
context.startService(意向);
打破;
}
}
}
}
mAUdioManager是AudioManager objectand mMediaButtonReceiverComponent是一个组件名,干脆把
AudioManager mAudioManager;
组件名mMediaButtonReceiverComponent;
调用方法lockScreenControls()之前。这些类的API 18
I am developing a music player. I have a widget that works on both the home and lock screen. I do not want to give the user the option to put or remove the widget from the lock screen.
My goal is:
The widget automatically appears on the host lock screen, removing the widget that there are as time-date widget, or putting over its.
Managing MusicService and Widget consistently. (Clear the widget from lock-screen when I leave the music player. That is exactly how the Google Play Music widget on my Galaxy Nexus (or many other phones). Is this possible? Is it possible that I need something that is not a widget, like custom lock screen?
解决方案
Well, the solution was simple, do not use any widget, simply use the RemoteControlClientCompat class. Here is my lockScreenControls() method code , which I call whenever I want to show this type of control.
private void lockScreenControls() {
// Use the media button APIs (if available) to register ourselves for media button
// events
MediaButtonHelper.registerMediaButtonEventReceiverCompat(mAudioManager, mMediaButtonReceiverComponent);
// Use the remote control APIs (if available) to set the playback state
if (mRemoteControlClientCompat == null) {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.setComponent(mMediaButtonReceiverComponent);
mRemoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this /*context*/,0 /*requestCode, ignored*/, intent /*intent*/, 0 /*flags*/));
RemoteControlHelper.registerRemoteControlClient(mAudioManager,mRemoteControlClientCompat);
}
mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
mRemoteControlClientCompat.setTransportControlFlags(
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
RemoteControlClient.FLAG_KEY_MEDIA_STOP);
//update remote controls
mRemoteControlClientCompat.editMetadata(true)
.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, "NombreArtista")
.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, "Titulo Album")
.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, nombreCancion)
//.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,playingItem.getDuration())
// TODO: fetch real item artwork
.putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK, getAlbumArt())
.apply();
}
}
***********EDIT************
RemoteControlClientCompat class:
@SuppressWarnings({"rawtypes", "unchecked"})
public class RemoteControlClientCompat {
private static final String TAG = "RemoteControlCompat";
private static Class sRemoteControlClientClass;
// RCC short for RemoteControlClient
private static Method sRCCEditMetadataMethod;
private static Method sRCCSetPlayStateMethod;
private static Method sRCCSetTransportControlFlags;
private static boolean sHasRemoteControlAPIs = false;
static {
try {
ClassLoader classLoader = RemoteControlClientCompat.class.getClassLoader();
sRemoteControlClientClass = getActualRemoteControlClientClass(classLoader);
// dynamically populate the playstate and flag values in case they change
// in future versions.
for (Field field : RemoteControlClientCompat.class.getFields()) {
try {
Field realField = sRemoteControlClientClass.getField(field.getName());
Object realValue = realField.get(null);
field.set(null, realValue);
} catch (NoSuchFieldException e) {
Log.w(TAG, "Could not get real field: " + field.getName());
} catch (IllegalArgumentException e) {
Log.w(TAG, "Error trying to pull field value for: " + field.getName()
+ " " + e.getMessage());
} catch (IllegalAccessException e) {
Log.w(TAG, "Error trying to pull field value for: " + field.getName()
+ " " + e.getMessage());
}
}
// get the required public methods on RemoteControlClient
sRCCEditMetadataMethod = sRemoteControlClientClass.getMethod("editMetadata",
boolean.class);
sRCCSetPlayStateMethod = sRemoteControlClientClass.getMethod("setPlaybackState",
int.class);
sRCCSetTransportControlFlags = sRemoteControlClientClass.getMethod(
"setTransportControlFlags", int.class);
sHasRemoteControlAPIs = true;
} catch (ClassNotFoundException e) {
// Silently fail when running on an OS before ICS.
} catch (NoSuchMethodException e) {
// Silently fail when running on an OS before ICS.
} catch (IllegalArgumentException e) {
// Silently fail when running on an OS before ICS.
} catch (SecurityException e) {
// Silently fail when running on an OS before ICS.
}
}
public static Class getActualRemoteControlClientClass(ClassLoader classLoader)
throws ClassNotFoundException {
return classLoader.loadClass("android.media.RemoteControlClient");
}
private Object mActualRemoteControlClient;
public RemoteControlClientCompat(PendingIntent pendingIntent) {
if (!sHasRemoteControlAPIs) {
return;
}
try {
mActualRemoteControlClient =
sRemoteControlClientClass.getConstructor(PendingIntent.class)
.newInstance(pendingIntent);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public RemoteControlClientCompat(PendingIntent pendingIntent, Looper looper) {
if (!sHasRemoteControlAPIs) {
return;
}
try {
mActualRemoteControlClient =
sRemoteControlClientClass.getConstructor(PendingIntent.class, Looper.class)
.newInstance(pendingIntent, looper);
} catch (Exception e) {
Log.e(TAG, "Error creating new instance of " + sRemoteControlClientClass.getName(), e);
}
}
/**
* Class used to modify metadata in a {@link android.media.RemoteControlClient} object. Use
* {@link android.media.RemoteControlClient#editMetadata(boolean)} to create an instance of an
* editor, on which you set the metadata for the RemoteControlClient instance. Once all the
* information has been set, use {@link #apply()} to make it the new metadata that should be
* displayed for the associated client. Once the metadata has been "applied", you cannot reuse
* this instance of the MetadataEditor.
*/
public class MetadataEditorCompat {
private Method mPutStringMethod;
private Method mPutBitmapMethod;
private Method mPutLongMethod;
private Method mClearMethod;
private Method mApplyMethod;
private Object mActualMetadataEditor;
/**
* The metadata key for the content artwork / album art.
*/
public final static int METADATA_KEY_ARTWORK = 100;
private MetadataEditorCompat(Object actualMetadataEditor) {
if (sHasRemoteControlAPIs && actualMetadataEditor == null) {
throw new IllegalArgumentException("Remote Control API's exist, " +
"should not be given a null MetadataEditor");
}
if (sHasRemoteControlAPIs) {
Class metadataEditorClass = actualMetadataEditor.getClass();
try {
mPutStringMethod = metadataEditorClass.getMethod("putString",
int.class, String.class);
mPutBitmapMethod = metadataEditorClass.getMethod("putBitmap",
int.class, Bitmap.class);
mPutLongMethod = metadataEditorClass.getMethod("putLong",
int.class, long.class);
mClearMethod = metadataEditorClass.getMethod("clear", new Class[]{});
mApplyMethod = metadataEditorClass.getMethod("apply", new Class[]{});
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
mActualMetadataEditor = actualMetadataEditor;
}
/**
* Adds textual information to be displayed.
* Note that none of the information added after {@link #apply()} has been called,
* will be displayed.
* @param key The identifier of a the metadata field to set. Valid values are
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
* @param value The text for the given key, or {@code null} to signify there is no valid
* information for the field.
* @return Returns a reference to the same MetadataEditor object, so you can chain put
* calls together.
*/
public MetadataEditorCompat putString(int key, String value) {
if (sHasRemoteControlAPIs) {
try {
mPutStringMethod.invoke(mActualMetadataEditor, key, value);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
return this;
}
/**
* Sets the album / artwork picture to be displayed on the remote control.
* @param key the identifier of the bitmap to set. The only valid value is
* {@link #METADATA_KEY_ARTWORK}
* @param bitmap The bitmap for the artwork, or null if there isn't any.
* @return Returns a reference to the same MetadataEditor object, so you can chain put
* calls together.
* @throws IllegalArgumentException
* @see android.graphics.Bitmap
*/
public MetadataEditorCompat putBitmap(int key, Bitmap bitmap) {
if (sHasRemoteControlAPIs) {
try {
mPutBitmapMethod.invoke(mActualMetadataEditor, key, bitmap);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
return this;
}
/**
* Adds numerical information to be displayed.
* Note that none of the information added after {@link #apply()} has been called,
* will be displayed.
* @param key the identifier of a the metadata field to set. Valid values are
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
* expressed in milliseconds),
* {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
* @param value The long value for the given key
* @return Returns a reference to the same MetadataEditor object, so you can chain put
* calls together.
* @throws IllegalArgumentException
*/
public MetadataEditorCompat putLong(int key, long value) {
if (sHasRemoteControlAPIs) {
try {
mPutLongMethod.invoke(mActualMetadataEditor, key, value);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
return this;
}
/**
* Clears all the metadata that has been set since the MetadataEditor instance was
* created with {@link android.media.RemoteControlClient#editMetadata(boolean)}.
*/
public void clear() {
if (sHasRemoteControlAPIs) {
try {
mClearMethod.invoke(mActualMetadataEditor, (Object[]) null);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
/**
* Associates all the metadata that has been set since the MetadataEditor instance was
* created with {@link android.media.RemoteControlClient#editMetadata(boolean)}, or since
* {@link #clear()} was called, with the RemoteControlClient. Once "applied", this
* MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
*/
public void apply() {
if (sHasRemoteControlAPIs) {
try {
mApplyMethod.invoke(mActualMetadataEditor, (Object[]) null);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
}
/**
* Creates a {@link android.media.RemoteControlClient.MetadataEditor}.
* @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
* was previously applied to the RemoteControlClient, or true if it is to be created empty.
* @return a new MetadataEditor instance.
*/
public MetadataEditorCompat editMetadata(boolean startEmpty) {
Object metadataEditor;
if (sHasRemoteControlAPIs) {
try {
metadataEditor = sRCCEditMetadataMethod.invoke(mActualRemoteControlClient,
startEmpty);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
metadataEditor = null;
}
return new MetadataEditorCompat(metadataEditor);
}
/**
* Sets the current playback state.
* @param state The current playback state, one of the following values:
* {@link android.media.RemoteControlClient#PLAYSTATE_STOPPED},
* {@link android.media.RemoteControlClient#PLAYSTATE_PAUSED},
* {@link android.media.RemoteControlClient#PLAYSTATE_PLAYING},
* {@link android.media.RemoteControlClient#PLAYSTATE_FAST_FORWARDING},
* {@link android.media.RemoteControlClient#PLAYSTATE_REWINDING},
* {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_FORWARDS},
* {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_BACKWARDS},
* {@link android.media.RemoteControlClient#PLAYSTATE_BUFFERING},
* {@link android.media.RemoteControlClient#PLAYSTATE_ERROR}.
*/
public void setPlaybackState(int state) {
if (sHasRemoteControlAPIs) {
try {
sRCCSetPlayStateMethod.invoke(mActualRemoteControlClient, state);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Sets the flags for the media transport control buttons that this client supports.
* @param transportControlFlags A combination of the following flags:
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD},
* {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT}
*/
public void setTransportControlFlags(int transportControlFlags) {
if (sHasRemoteControlAPIs) {
try {
sRCCSetTransportControlFlags.invoke(mActualRemoteControlClient,
transportControlFlags);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public final Object getActualRemoteControlClientObject() {
return mActualRemoteControlClient;
}
}
RemoteControlHelper class:
public class RemoteControlHelper {
private static final String TAG = "RemoteControlHelper";
private static boolean sHasRemoteControlAPIs = false;
private static Method sRegisterRemoteControlClientMethod;
private static Method sUnregisterRemoteControlClientMethod;
static {
try {
ClassLoader classLoader = RemoteControlHelper.class.getClassLoader();
Class sRemoteControlClientClass =
RemoteControlClientCompat.getActualRemoteControlClientClass(classLoader);
sRegisterRemoteControlClientMethod = AudioManager.class.getMethod(
"registerRemoteControlClient", new Class[]{sRemoteControlClientClass});
sUnregisterRemoteControlClientMethod = AudioManager.class.getMethod(
"unregisterRemoteControlClient", new Class[]{sRemoteControlClientClass});
sHasRemoteControlAPIs = true;
} catch (ClassNotFoundException e) {
// Silently fail when running on an OS before ICS.
} catch (NoSuchMethodException e) {
// Silently fail when running on an OS before ICS.
} catch (IllegalArgumentException e) {
// Silently fail when running on an OS before ICS.
} catch (SecurityException e) {
// Silently fail when running on an OS before ICS.
}
}
public static void registerRemoteControlClient(AudioManager audioManager,
RemoteControlClientCompat remoteControlClient) {
if (!sHasRemoteControlAPIs) {
return;
}
try {
sRegisterRemoteControlClientMethod.invoke(audioManager,
remoteControlClient.getActualRemoteControlClientObject());
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
public static void unregisterRemoteControlClient(AudioManager audioManager,
RemoteControlClientCompat remoteControlClient) {
if (!sHasRemoteControlAPIs) {
return;
}
try {
sUnregisterRemoteControlClientMethod.invoke(audioManager,
remoteControlClient.getActualRemoteControlClientObject());
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
To Change lockPlayer State dinamicaly:
private void lockontrolsPlay() {
if (mRemoteControlClientCompat != null) {
mRemoteControlClientCompat
.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
}
}
private void lockontrolsPause() {
if (mRemoteControlClientCompat != null) {
mRemoteControlClientCompat
.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
}
}
The receiver:
public class MusicIntentReceiver extends WakefulBroadcastReceiver {
private int headsetSwitch = 1;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
Toast.makeText(context, MyApplication.getContext().getResources().getString (R.string.aptxt15), Toast.LENGTH_SHORT).show();
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "pause_cascos");
context.startService(intent);
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if (keyEvent.getAction() != KeyEvent.ACTION_DOWN)
return;
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "pause");
context.startService(intent);
// context.startService(new Intent(MusicService.ACTION_TOGGLE_PLAYBACK));
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
// context.startService(new Intent(MusicService.ACTION_PLAY));
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "pause");
context.startService(intent);
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
// context.startService(new Intent(MusicService.ACTION_PAUSE));
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "pause");
context.startService(intent);
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
// context.startService(new Intent(MusicService.ACTION_STOP));
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "next");
context.startService(intent);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
// TODO: ensure that doing this in rapid succession actually plays the
// previous song
// context.startService(new Intent(MusicService.ACTION_REWIND));
intent = new Intent(context, ReproductorDialog.ServicioCanciones.class);
intent.putExtra("do_action", "previous");
context.startService(intent);
break;
}
}
}
}
mAUdioManager is an AudioManager objectand mMediaButtonReceiverComponent is a ComponentName, simply put
AudioManager mAudioManager;
ComponentName mMediaButtonReceiverComponent;
before call method lockScreenControls(). These Classes are on API 18