Presentation on theme: "WIDGET PLAYER STEPHEN NEWBY. WHAT ARE WIDGETS? Widgets are placed on the Android device’s home screen Can be added, removed, resized, moved at will Stay."— Presentation transcript:
WIDGET PLAYER STEPHEN NEWBY
WHAT ARE WIDGETS? Widgets are placed on the Android device’s home screen Can be added, removed, resized, moved at will Stay active, performing their task, even when Apps are open Many different widgets to choose from Some installed by default Others in Play store developed by 3 rd parties
WIDGET PROGRAMMING 101 Widgets cannot be directly interacted with Must use Intents, PendingIntents, RemoteViews, Service to operate Very limited subset of Views and Layouts that can be used to create UI Layouts: FrameLayout, LinearLayout, RelativeLayout, GridLayout Views: AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView, AdapterViewFlipper Descendants of these classes are NOT supported
WIDGET PROGRAMMING 101 Activity and Fragment are NOT used Can still be included and manually started for things like Dialogs that you might want to show during operation Can also (optionally) specify a configuration Activity to launch when the widget is placed by the user, which will send an Intent to the widget when the Activity finishes
WIDGET PROGRAMMING 101 Cannot directly interact with Views in the widget To update a Layout or View, you must create a RemoteViews object -- use it to describe what changes you want to apply -- and then use an AppWidgetManager to send the RemoteViews object to the specific widget(s) you want updated Don’t forget to make a new RemoteViews object for changes after you call the AppWidgetManager -- If you forget, all the old changes will run again along with the new This must still occur in the UI thread, just like an App! Typically performed in a Service that is started in the first call to a WidgetProvider’s onUpdate() entry point when the first copy of a widget is placed
WIDGET PROGRAMMING 101 User input is achieved by attaching a PendingIntent to a Button (or any View) using a RemoteViews object – this PendingIntent is then sent by the OS when the view generates the method that the PendingIntent was attached to, such as onClick() PendingIntent works much like a Messenger or Handler – you specify to whom it goes (your Service, hopefully!), and attach some data to it to be unpacked and acted upon when received
WIDGET PROGRAMMING 101 To be able to be placed on the home screen and launched, a widget MUST have: An entry class that extends WidgetProvider and implements onUpdate() -- this method can be empty if you just want the widget to show up A proper node for this WidgetProvider inside the node of the AndroidManifest.xml An xml file with an root node that specifies the base properties of the widget (such as which layout xml file to use), to be referenced in the AndroidManifest.xml A layout xml file that does not use any Layout or View not supported by widgets
WIDGET DEBUGGING Debugging widgets is painful Crash report (stack dump) often points you at the wrong place due to how deep the call stack gets and how tangled the program flow eventually gets If your widget crashes, typically you try to fix the code, upload the new version, and see if it works Android “helpfully” caches widgets to speed up loading the home screen This fails badly when Android decides to keep using the cached version instead (I fixed it, I swear!) and your widget just keeps crashing in the same way Must uninstall the widget and reboot the phone/tablet to clear Android’s cache! The execution path through your code is almost never what you expect, due to having many entry points, possibly non-persistent state, and a Service running with it’s own state in the background
OKAY! WIDGETS! WOO!
WIDGET PLAYER - ORIGIN Existing music player apps and widgets expect you to use your phone as… a phone I don’t use my device as a phone, it has no service, and it’s locked to Verizon I don’t care about playlists, I prefer random play, or to listen to an entire album I really like album art a lot I don’t care about “Stars” or rating songs – If the song or album isn’t awesome, I don’t want it on my device! Existing player apps and widgets do not meet my preferred usage model Why not get an MP3 player then? The phone was free! It’s hard to beat free!
WIDGET PLAYER - GOALS Allow phone to act first as an MP3 player, second as a phone/Android device Fast startup and track selection BIG album art Be the default screen for the device Good randomization of songs Album or Track randomization Mark some tracks as “Album Only” so they are not considered by the track selector while in fully random mode – for short or odd tracks that only make sense when listening to an entire album
WIDGET PLAYER - SIMPLIFIED STARTUP Widget Placed onUpdate() Starts Service by: Registers itself with Service Service Started onStartCommand() Handles widget registration Initializes widget UI Presents as a state-machine driven by Intents MediaPlayer
MEDIA PLAYER MediaPlayer handles audio playback on Android It’s very picky – If you fail to follow the state diagram for it, it will crash your App/Widget, and it will laugh at you Widget Player’s Service manages both the widget UI and a MediaPlayer object Alternative is writing code to dig into the default Android music player and trigger it to play music – Workable but: Has no API – Method of interaction can change with each Android version update Would require to detect Android version and have separate custom API for every different music player version supported This is Bad
WIDGET PLAYER - SERVICE Brains of the widget Complex state-machine that has many entry points onCreate(), onDestroy() – Lifecycle onStartCommand() – Intent and PendingIntent entry point, this is the “meat” of the Service onPrepared(), onCompletion(), onError() – MediaPlayer asynchronous entry points onAudioFocusChange() – Android OS entry point for gaining/losing audio focus handleMessage() – Used as a timer to create regular “ticks” for updating the song playback progress File reading -- Album Art and MP3 audio and ID3 data -- is done in a separate thread, the Service is notified when these long-running operations finish so that it can update the widget UI and start playback
WIDGET PLAYER - RESULTS Fast startup and track selection Player is ready to go instantly as soon as the SD card is mounted BIG album art Will load from track ID3 artwork, if available If no ID3 artwork in track, displays the first image found in the same folder as the track file If no artwork found anywhere, displays a default “No Artwork” Allows phone to act first as an MP3 player, second as a phone/Android device The default screen for the device Being a widget, it is always active, and always on the home screen Super easy to get back to – Press home button! Fairly robust Handles USB Storage events, and SD card vanishing Handles headphones being unplugged Handles corrupt album art images Handles corrupt or unknown audio file formats
WIDGET PLAYER TODO Album or Track randomization Need to find a place to put some visible UI element for toggling this Good randomization – current random is acceptable, but could be much better Marking of tracks as “Album Only” and to be skipped in Track Random Maybe add a Repeat option? Would repeat track in Track mode, or entire album in Album mode Need to find a place to put some visible UI element for toggling this Cache album art Art that is larger than the widget area must be scaled down to fit Scaling is slow! Currently doing reading/scaling in a thread and updating when done Should cache the scaled version and use that instead to improve speed
WIDGET PLAYER - KNOWN BUGS Losing audio focus (ducking) is coded for, but untested Incoming call would trigger it – not sure what else Don’t have service, no good way to test Unmount/Remount of SD Card works, but isn’t handled perfectly yet – Widget is restarted by Android and loses state
WIDGET PLAYER WISHLIST Lock Screen support – So you don’t have to unlock device to pause or change tracks Touch input on position indicator Cannot directly interact with most widget UI elements Touch requires direct interaction Can be “hacked” in with some very creative and tricky Java programming Track Tagging Not ID3 tags Specific to Widget Player Can be implemented with ID3 tags, or anything else suitable More than just Genre – Sounds Like, Singer, Influences, Mood… anything! Track selection based on tagging -- Play anything tagged with “Jørn Lande” Better contrast for track information Not sure how to implement while keeping album art huge and visible Detect “empty” space at the end of a track and skip over it Gaps at the end of songs are annoying when listening!