30 Jul 2020
These days most people use their mobile phones as music players, unlike the old days when most people had an ipod or simliar mp3 player for their music listening on the go. Still high end players do still exist as "DAP's" (Digital Audio Players) along with really cheap and nasty basic mp3 players. But both suffer from either badly designed UI's or UI's that are overly complex, or both, while the cheap players also have rather poor quality hardware as well. None are really suitable for my use case of: being used by a first grader who just wants to listen to some songs or a radio-play during a long car trip.
Being a software developer however, I was in the privileged position of being able to choose to take a DIY approach and make my own and so I've documented my little journey into DAP-making here to help anyone else who would like to try this approach.
Starting with the hardware, I briefly considered taking a DIY approach of something like a Raspberry Pi Zero paired with a Pimoroni pirate audio board and custom 3d printed case, but decided that it would be rather more time consuming then I wanted to and the physical controls and tiny screen still probably would not be well suited for my use case. So instead I went with an idea I'd had a while ago: turn an old android phone into a DAP! Since I already had a couple of appropriately small screen (3.5 & 4in) "ancient" (Android 4.4) phones lying around in a draw that had been retired from my test phone suite I didn't even need to go out to buy them, which is very helpful in these locked-down times.
The other key feature that both these phones had was a micro-sdcard slot, which meant their tiny internal flash storage could be nicely expanded with 32 and even 64gb!! cards. Yes! even though it was not documented, I was able to get the larger ZTE B816 to accept a 64gb sdcard without any issues.
The other great thing about these phones is just how cheaply they can be had, even when I bought them years ago, they were only on specials for AUD$19-29 at local woollies and coles supermarkets and similar (newer) models still often come up on sale at supermarkets or AusPost shops at similiar prices.
With the hardware taken care of, the software part of the project also fell into place. Essentially what I needed was an Android music player app that could be turned into a "launcher" aka "home screen" app for the phones. Something that is maybe not so well known these days, is that on Android, any app with an appropriate intent filter can be designated as the default launcher app for the device by the user without requiring any special permissions. Given that both phones came with a reasonable basic music player app, I briefly contemplated just using it and directly running it from a simple launcher "wrapper" app, but I wanted to keep the option open to modify the player UI, mainly to focus on keeping it simple and usable by the target (6 year old) audience, so I decided to look at choosing from an existing Android open source music player app.
Surprisingly there is quite a large selection of open source Android music player apps to choose from! However in keeping with current focus on Flutter development, I ended up choosing an existing music app built in Flutter, appropriately named: Flutter-Music-Player by a well known member of the community Pawan Kumar.
Having chosen to use the Flutter-Music-Player, I did unfortunately find that it seems to no longer be actively maintained by Pawan, so I ended up needing to fork both it and the underlying Flute-Music-Player Flutter plugin that provides the key functionality that allows for integrating with the MediaStore database on Android. This integration means that instead of having to try and find where the users music is located on the device and parse each music files metadata and then maintain a database of it all, the app can simply make use of all this functionality already built into the Android framework and made available via a content resolver api.
I called my fork of the music player app music-home, because apart from fixing some issues with the existing code, such as making the UI fullscreen and fitting on a small, low-resolution screen of the old phones I was using (especially the 3.5in, 480x320 one):
I also modified the app to be a Android launcher. As I mentioned previously, this actually only requires a small addition of a extra intent filter in the apps manifest:
<intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.HOME"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
Once the app is installed, pressing the Home button on the device will prompt the user to choose which "launcher" app to use, and on Android Kitkat, which both phones are running, it allows this just by pressing the "Always" button on that dialog:
to make music_home app the default and hence be run each time the user presses the Home button from that point on, as well as after each device reboot.
And with that I had my DAP players ready to go:
Well almost ready.
Given that I was using them only as DAP's, I made sure to put the phones into Flight-Mode which greatly increased their battery runtimes. This included keeping BT off as currently we are only using wired headphones, though having the option to use BT is another great benefit of using these old phones as the hardware platform for this project.
Overall I'm very happy with how this project turned out. As with any project, I wasn't able to get everything I wanted done, so I have a few feature todo's left for the player app and would also like to investigate a means of "rooting" the devices to allow me to strip out extraneous apps and services pre-installed on the system partitions of the phones which would improve device startup times.
While I've covered here my very specific use case, this simple example shows how easily Android devices, even very low-end consumer ones, can be easily re-purposed into single function "embedded" devices, all thanks to the openness and flexibility of the Android operating system and its oem ecosystem, which is simply unimaginable in the walled-garden of Apple and iOS.
This experiment has also demonstrated for me that Flutter is able to provide excellent graphical UI performance on even very low-end devices, supports even very old (ancient!) versions of Android and so would be an excellent choice for building custom UI's in vertical markets such as car head units and airline in-seat entertainment systems and many other single purpose embedded environments where a pleasant and performant UI would be a valuable product differentiator, while Flutter provides an exceptionally productive environment for developers. Of course this is not something that has only occurred to me and is evidenced by Googles own use of Flutter in its embedded consumer products.