{"id":8447,"date":"2014-01-16T10:00:39","date_gmt":"2014-01-16T18:00:39","guid":{"rendered":"http:\/\/blog.xamarin.com\/?p=8447"},"modified":"2014-01-16T10:00:39","modified_gmt":"2014-01-16T18:00:39","slug":"lock-screen-music-controls-in-xamarin-android","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/lock-screen-music-controls-in-xamarin-android\/","title":{"rendered":"Lock Screen Music Controls in Xamarin.Android"},"content":{"rendered":"<p>\t\t\t\tStreaming audio in a background service with <a href=\"http:\/\/www.xamarin.com\/android\" title=\"Create Android apps in C# with Xamarin\" target=\"_blank\">Xamarin.Android<\/a> allows developers to create amazing user experiences. In my <a href=\"\/background-audio-streaming-with-xamarin.android\" title=\"Background Audio Streaming with Xamarin.Android\" target=\"_blank\">last post<\/a> I walked though how to setup the a basic streaming service with a notification that your users could interact with. In Ice Cream Sandwich (API 14) Google introduced the <strong><a href=\"http:\/\/androidapi.xamarin.com\/?link=T%3aAndroid.Media.RemoteControlClient\" title=\"Remote Control Client API Doc\" target=\"_blank\">RemoteControlClient<\/a><\/strong>, which exposes properties and methods be consumed by remote controls capable of displaying metadata, artwork and media transport control buttons. One of these &#8220;remote controls&#8221; is built into the lock screen of devices.<\/p>\n<p style=\"text-align: center\"><a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/IMG_20131108_171118.jpg\"><img decoding=\"async\" class=\"aligncenter  wp-image-8448\" alt=\"IMG_20131108_171118\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/IMG_20131108_171118.jpg\" width=\"432\" height=\"192\" \/><\/a><\/p>\n<p>Since we already have a base streaming music service in place it is actually quite easy to take advantage of the RemoteControlClient to add lock screen music controls to our application. <\/p>\n<p>A RemoteControlClient communicates with our application through Intents, specifically the <strong>Intent.ActionMediaButton<\/strong> which will be broadcast when our users press one of the buttons on the lock screen. We will first want to create a new BroadcastReceiver to handle any of these broadcasts to process them and pass the correct command to our background service. Here is what our BroadcastReciver looks like to handle these button presses:<\/p>\n<pre class=\"lang:csharp decode:true\">\n[BroadcastReceiver]\n[Android.App.IntentFilter(new []{Intent.ActionMediaButton})]\npublic class RemoteControlBroadcastReceiver : BroadcastReceiver\n{\n  public string ComponentName { get { return this.Class.Name; } }\n\n  public override void OnReceive (Context context, Intent intent)\n  {\n    if (intent.Action != Intent.ActionMediaButton)\n      return;\n\n    \/\/The event will fire twice, up and down.\n    \/\/ we only want to handle the down event though.\n    var key = (KeyEvent) intent.GetParcelableExtra(Intent.ExtraKeyEvent);\n    if (key.Action != KeyEventActions.Down)\n      return;\n    var action = StreamingBackgroundService.ActionPlay;\n    switch (key.KeyCode) {\n      case Keycode.Headsethook:\n      case Keycode.MediaPlayPause: action = StreamingBackgroundService.ActionTogglePlayback; break;\n      case Keycode.MediaPlay: action = StreamingBackgroundService.ActionPlay; break;\n      case Keycode.MediaPause: action = StreamingBackgroundService.ActionPause; break;\n      case Keycode.MediaStop: action = StreamingBackgroundService.ActionStop; break;\n      case Keycode.MediaNext: action = StreamingBackgroundService.ActionNext; break;\n      case Keycode.MediaPrevious: action = StreamingBackgroundService.ActionPrevious; break;\n      default: return;\n    }\n    var remoteIntent = new Intent(action);\n    context.StartService(remoteIntent);\n  }\n}\n<\/pre>\n<p>Once we have our BroadcastReceiver in place, back in our service we are going to create three new methods. The first is to create and register the RemoteControlClient, second is to unregister it, and the last is to update the metadata for the lock screen to display.<\/p>\n<p>First up is our register method, which will register our BroadcastReceiver with the <strong>AudioManager<\/strong> to allow it to receive broadcasts and specifies the correct intent to trigger. The last thing the method will do is set the correct <strong>RemoteControlFlags<\/strong> that we can process. This method will be called when we start or resume playback.<\/p>\n<pre class=\"lang:csharp decode:true\">\nprivate ComponentName remoteComponentName;\nprivate void RegisterRemoteClient()\n{ \n  remoteComponentName = new ComponentName(PackageName, new RemoteControlBroadcastReceiver().ComponentName);\n  try {\n    if(remoteControlClient == null) {\n      audioManager.RegisterMediaButtonEventReceiver(remoteComponentName);\n      \/\/Create a new pending intent that we want triggered by remote control client\n      var mediaButtonIntent = new Intent(Intent.ActionMediaButton);\n      mediaButtonIntent.SetComponent(remoteComponentName);\n      \/\/ Create new pending intent for the intent\n      var mediaPendingIntent = PendingIntent.GetBroadcast(this, 0, mediaButtonIntent, 0);\n      \/\/ Create and register the remote control client\n      remoteControlClient = new RemoteControlClient(mediaPendingIntent);\n      audioManager.RegisterRemoteControlClient(remoteControlClient);\n    }\n  \/\/add transport control flags we can to handle\n  remoteControlClient.SetTransportControlFlags(RemoteControlFlags.Play | \n\t\t\t\t\t       RemoteControlFlags.Pause |\n\t\t\t\t\t       RemoteControlFlags.PlayPause |\n\t\t\t\t\t       RemoteControlFlags.Stop | \n\t\t\t\t\t       RemoteControlFlags.Previous |\n\t\t\t\t\t       RemoteControlFlags.Next);\n  }catch(Exception ex) {\n    Console.WriteLine (ex);\n  }\n}\n<\/pre>\n<p>Whenever we stop music playback we want to ensure that we unregister the RemoteControlClient as we no longer need to display the lock screen controls.<\/p>\n<pre class=\"lang:csharp decode:true\">\nprivate void UnregisterRemoteClient()\n{\n  try{\n    audioManager.UnregisterMediaButtonEventReceiver (remoteComponentName);\n    audioManager.UnregisterRemoteControlClient (remoteControlClient);\n    remoteControlClient.Dispose();\n    remoteControlClient = null;\n  }catch(Exception ex){\n    Console.WriteLine (ex);\n  }\n}\n<\/pre>\n<p>Lastly, we can update the lock screen with the metadata we want to display. Calling the RemoteControlClient&#8217;s <strong>EditMetadata<\/strong> method will return a new MetadataEditor that allows us to set a plethora of information to be displayed with MetadataKeys. In this example I am hard coding in the song I am playing back with album artwork located in my drawables, but you might dynamically pass this information down to your service and download the artwork to display. <\/p>\n<pre class=\"lang:csharp decode:true\">\nprivate void UpdateMetadata()\n{\n  if (remoteControlClient == null)\n    return;\n\n  var metadataEditor = remoteControlClient.EditMetadata(true);\n  metadataEditor.PutString (MetadataKey.Album, &quot;Fantastique&quot;);\n  metadataEditor.PutString (MetadataKey.Artist, &quot;Raw Stiles&quot;);\n  metadataEditor.PutString (MetadataKey.Albumartist, &quot;Raw Stiles&quot;);\n  metadataEditor.PutString (MetadataKey.Title, &quot;Rogue&quot;);\n  var coverArt = BitmapFactory.DecodeResource(Resources, Resource.Drawable.album_art);\n  metadataEditor.PutBitmap (BitmapKey.Artwork, coverArt);\n  metadataEditor.Apply ();\n}\n<\/pre>\n<p>With these methods in place we just have to update our Start, Pause, and Stop logic to call these methods. Additionally, the RemoteControlClient has the <strong>SetPlaybackState<\/strong> method that we will set to Playing, Paused, Stopped, or Buffering so the lock screen will display the correct icons for each state. Now when we set the audio to playback we will register the RemoteControlClient, update the state, and set the metadata:<\/p>\n<pre class=\"lang:csharp decode:true\">\nRegisterRemoteClient ();\nremoteControlClient.SetPlaybackState(RemoteControlPlayState.Buffering);\nUpdateMetadata();\n<\/pre>\n<p>After the song is prepared we will again update the state and ensure the correct metadata is showing:<\/p>\n<pre class=\"lang:csharp decode:true\">\nplayer.Prepared += (sender, args) =&gt; {\n  if(remoteControlClient != null)\n    remoteControlClient.SetPlaybackState(RemoteControlPlayState.Playing);\n  UpdateMetadata ();\n  player.Start ();\n};\n<\/pre>\n<p>There you have it, a simple way to add great functionality to your audio streaming app. Try this project in Visual Studio, or run this Starter-compatible project in Xamarin Studio on Mac or Windows. I have the full source code available on <a href=\"https:\/\/github.com\/jamesmontemagno\/AndroidStreamingAudio\" title=\"Android Streaming Audio on GitHub\" target=\"_blank\">GitHub<\/a>, along with my original example of setting up the base streaming service.<\/p>\n<p><a href=\"http:\/\/forums.xamarin.com\/discussion\/12058\" title=\"Discuss this blog on the Xamarin Forums\" target=\"_blank\"><em>Discuss this blog post in the Xamarin Forums<\/em><\/a>\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Streaming audio in a background service with Xamarin.Android allows developers to create amazing user experiences. In my last post I walked though how to setup the a basic streaming service with a notification that your users could interact with. In Ice Cream Sandwich (API 14) Google introduced the RemoteControlClient, which exposes properties and methods be [&hellip;]<\/p>\n","protected":false},"author":544,"featured_media":39167,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[5,4],"class_list":["post-8447","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-android","tag-xamarin-platform"],"acf":[],"blog_post_summary":"<p>Streaming audio in a background service with Xamarin.Android allows developers to create amazing user experiences. In my last post I walked though how to setup the a basic streaming service with a notification that your users could interact with. In Ice Cream Sandwich (API 14) Google introduced the RemoteControlClient, which exposes properties and methods be [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/8447","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/544"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=8447"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/8447\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/39167"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=8447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=8447"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=8447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}