LPA managing application - Android Software Development

Hi,
I'm currently trying to develop an android application to manage eSIM profiles including functions to download, enable, disable, delete profile. However at the current stage, I'm unable to even hit the LPA code while attempting to download the profile from a hardcoded LPA string within the code.
My download profile code for reference:
---------------------------------------------------------------------------
euiccManager.downloadSubscription(
downloadableSubscription,
true,
callbackIntent
)
//where downloadableSubscription:
private lateinit var downloadableSubscription: DownloadableSubscription //from.....import android.telephony.euicc.DownloadableSubscription
downloadableSubscription = DownloadableSubscription.forActivationCode("String_value_of_the_activation_code")
---------------------------------------------------------------------------
I'm sure the function is being executed since I've defined 2 toast prints before and after the function and they are showing up fine on the device.
API:33
Phone: Google Pixel 4
APK is a signed release using self-signed certificate (this self signed certificate's hashvalue is also being configured on the metadata of the Profile I'm trying to download, so I'm wondering this shouldn't be a problem during the signature match check)
Also for some context I work in a company that deals in such subscription service management, and I'm testing the possibility of developing an inhouse app to work-around the profiles.

Related

Application idea - camera (read barcode), and send data to ip address

I want to create an application or two, and the first one I want to do must be able to:
using a "chart", assign a numeric value to various barcode symologies... 1 for UPCA, 2 Code 39, etc
Read a barcode with the camera
"decode" the barcode symbology and create a value for the scanned bc
Cache the data from the decode and symbology
open a text file
Write that barocode symbology value to a file
Write that barcode data to the file on the phone or sd card
save the change
Send the file to an ip address and port that is configured by the user.
What I can already do with terminal emulation apps (in Windows or Android apps) is log into the ip address of a embedded wireless device, and configure the device through a console. I would like to send it a script instead. By scanning a barcode from a scanboard, I could take a value from that barcode and inject it into a file that is already mostly scripted, but with the value of the barcode as the only part that is missing. Once scanned, then written to the file, it could automatically or through a button press, send the file to the ip address to configure the device.
Since some barcodes might be code 39, upca, code 128, etc, each of those barcodes must be programmed into my script. So if I scan a code 39 barcode, the script might call that a value of 2, and then I place that 2 in my script along with the data in the code 39 barcode. With 2 variables always in play, type of barcode and data from the barcode read, that's what always has to be in the script.
Now for the hard part, at least for me. I have been working with App Inventor, and found that they do not have a TCP module, and do not believe that AI is where I should be to make this app. My question is for anyone familiar with programming TCP/sockets, or whatever other networking name it would be called, and another form of programming for the creation of this type of app. I am already working in Eclipse, and the learning curve for me is high because of the lack of time I am able to spend with the beast of a utility. As much as I would love to build this app myself, I would consider paying someone to create it for me as long as I could have the source and continue to modify it after the fact and call it my own. PM me your price, but please remember that I have an ex wife that is already bleeding me to death and that I would prefer to work on this app myself, so I am more interested in a nudge or push in the right direction to create the app.
Long of the short, it's a scanner app that allows me to inject the data read from the barcode into a text file and then send the file to an ip. if I could find a telnet app (ip and port configurability) that allowed me to send text files, I would be partially there, so instead I strive to create.
Anyone?
Thanks in advance,
Standupdad
There should be lots of tutorials on TCP/IP and URL connections you can probably google up.
That's actually the easier of the two tasks. However for scanning the barcode, you're also in luck: zxing's library for barcode and QR code scanning is opensource (and it's excellent). It will take a bit to learn how to integrate it into your app, or you can have the users download the BarcodeScanner app and just communicate from your app to the Bacrode scanner app with it with Intents.
http://code.google.com/p/zxing/

[Problem] Android SQLIte Database Development, "getDatabase called recursively"

[Problem] Android SQLIte Database Development, "getDatabase called recursively"
Morning, mates.
I'm having a serious problem right now and hope you can help.
I'm writing a tool for android that utilizes a database. Here' is what happens:
As soon as the first request is sent to the DatabaseHandler i wrote, the app crashes with an
02-24 10:45:54.636: E/AndroidRuntime(10845): java.lang.IllegalStateException: getDatabase called recursively
After some digging, that included decompiling the android.jar (only contains API stubs, yay) i've found, that the onCreate Method is called more often than it should. I suspect a problem in storing the database.
To confirm that i need to have a look at the current SQLiteOpenHelper.class which i cannot find anywhere.
I will share code as needed, but as it is a commercial project i cannot post it in public.
I'm grateful for every hint/clue/tip whatsoever, this is costing me sleep.
Max

[XAP][Source] Webserver v0.6.0 (File uploads)

Version Alpha 0.6.0 is now available
I'm back! Not dead yet, I promise. This is actually a relatively small update in terms of user-facing features, with only one really big new thing - support for file uploading - but that's a lot bigger than it might sound. It's the first write support I've implemented in the server, and it also required some fairly massive updates to the HttpServer component (support for binary requests, for POST parameters, for MIME multipart parsing). These will be built upon in forthcoming versions to add support for things like registry editing, in-browser file viewing (possibly editing), and so on. There are also a large number of small fixes and improvements that I've made over the last two-weeks-shy-of-a-year, which should make the server faster, more robust, better able to support concurrent connections, and lighter on device resources. Finally, while the app still targets WP8.0 and should run on 8.0, it now is designed for 8.1 compatibility (especially the AllCapabilities version).
Previous update (0.5.6): This version is mostly bug fixes and UI changes. The biggest changes are: clearer display of weird registry data types, the server now consumes fewer threads (it used to spawn them with wild abandon) and does faster string compares, the app version is now shown on the phone, error pages are now better, if you launch the app without a WiFi IP address it'll offer to take you to the WiFi settings page, connections are no longer closed as soon as the app starts sending a response, and the server now defaults to using the Connection: keep-alive header, with a two-minute timeout. The last change, combined with the second-to-last, should hopefully both do away with the tendency to have the app fail to display a page. However, I shouldn't have *needed* to switch it to "keep-alive" - using "close" should have worked - but it still veeeery occasionally would kill the connection early. Agh. Anyhow, this is better in the meantime.
DevDB offers me a support / Q&A thread. Please use that thread to ask questions; don't PM me unless it needs to be kept private for some reason!
ISSUES ON WP8.1:
It *should* work to deploy the app with "Application Deployment", but if you have a problem try deploying with "Windows Phone Application Deployment 8.1" instead.
Problems have been reported in the past when the app is installed to the SD card. It's small, though; putting it on internal storage shouldn't be a problem.
RESOLVED The AllCapabilities version included a few capabilities that were present in 8.0 but removed in 8.1. Those capabilities have been removed; the AllCapabilities version now deploys and runs on capability-unlocked WP8.1 phones.
IN CASE OF OTHER ISSUES: Please provide a *detailed* error report - what phone and OS version you have, what hacks you've installed, what Webserver version you're running, what you do to get the error to occur, and exactly *what* occurs - and I'll fix it as soon as I can! There's a DevDB section for posting bug reports, and you can also use CodePlex if you want.
I finally implemented file upload! I'll work on getting more stuff like that (file delete, possibly file rename/move/copy, various registry edits), hopefully soon! I also hope to add support for different areas, like an "Applications" path, a "Processes" path, a "Services" path... eventually. Many of those are really hard without good privileges. I'm also looking at moving the server to a background process and making the app just a control UI for it, adding support for authentication and/or HTTPS, adding some stylesheets to the web UI, adding caching, and much more. I did finally implement Connection header support.
Once again, the XAP is published twice. One is a fairly standard XAP that any phone can sideload, and the second has many exotic capabilities to enable viewing of (and writing to) slightly more of the file system and registry. The standard XAP has had its list of capabilities expanded to pretty much all of them that can be used without interop-unlock. The high-capability variant requires not just interop-unlock, but the additional capability-unlock hack available in the interop-unlock thread. The AllCapabilities version now works with WP8.1; sorry for the long delay on that!
An item of note: the AllCapabilities version (or either version, on WP8.1) can open other drives in the file system. On phones with an SD card, it is mounted at D: and you can browse it as normal. Credit to @hjc4869 for this discovery!
DESCRIPTION: This is a simple webserver app which can enumerate those files that are in folders readable from the sandbox, can download and upload (access permitting) files, can browse the registry, and can display the contents of registry values of any type. It runs on WP8.x (not yet tested on W10M). It is a spiritual successor to the Functional Webserver / WebServer (Mango) projects from WP7. This version is still missing a lot of functionality as I decided to implement it from scratch, but it is advancing swiftly. Note that there's no access controls implemented; use it on a public network only at your own risk!
Instructions are simple: sideload the XAP, connect to WiFi (required), run the app (called "WebServer Native Access"), point a web browser (on a PC or phone that is also on that local network) to the URL that the app displays. You should get a basic index page. Click on a Filesystem or Registry link to begin browsing the phone. There's a textbox near the top of all filesystem pages, type in a path there (for example, "C:windows" with no quotes) and hit Enter or click Get Files. You'll see a list of the contents of that folder. Click on a file to download it or a directory to open it. There's also a box for uploading files, one at a time, to the current directory. Navigating the registry is similar, except you'll need to specify the registry hive and then the path from that hive (or no path, to access the root of the hive).
As of v0.6.0, uploading files is finally supported! Other modifications (editing files, creating, deleting, or changing registry keys or values) are currently not supported. They will be "soon" although my personal testing suggests that basically the whole registry, and most of the file system, is off-limits for writing unless you use restricted capabilities.
You might see an error code (error 5 is "ACCESS_DENIED", you'll see it a lot; I should replace it with an appropriate 403 or whatever). Or you might see a status 500 message because of an exception in the server. Or the server may just crash (hopefully not so often anymore...). I'm making it more resilient, but there are still bugs. Please report any previously-unreported issues you find, including how to reproduce them, and I'll fix them if possible.
Also feel free to request features or changes; I'll implement them if reasonably possible. The app is a mixture of C++ and C# code; I could probably have done it all in one or the other but wanted to have a C++ component in case I ran into something that wasn't available in C#, and although it probably would have saved some time, I decided that hacking up a web server in C++ was maybe not the best idea.
The source code is on Codeplex, at the following projects: https://wp8webserver.codeplex.com/ for the server and the app (C#) and https://wp8nativeaccess.codeplex.com/ for the native access wrappers (C++). You may have to fix up the reference paths to get the C# component to see the C++ component correctly. The code is reasonably well documented, but let me know if you have any questions. Permission to re-use the code or components is granted under the MS-PL (Microsoft Permissive License) as posted on Codeplex.
Go forth and find cool stuff!
Version history (see the git commit logs for more detail:
07 July 2013 - 0.2.0: Initial release, FS only, 920 downloads (source: 652 downloads)
14 July 2013 - 0.3.2: initial registry, HTTP server and web app encapsulation, source on Codeplex, 225 downloads
0.3.3: bugfixes, 454 downloads
0.4.2: basic registry values display, 86 downloads
0.4.3: bugfixes, 326 downloads
0.4.6: multistring registry values, bugfixes, updated libraries, first AllCapabilities version (950 downloads), 453 downloads
25 Oct 2013 - 0.4.8: binary and long registry values, formatting and bugfixes, 451 downloads AllCaps, 201 normal
22 Dec 2013 - 0.4.9: all registry value types, better threading, proper resume, remembers port, 97 downloads AllCaps, 53 normal
24 Dec 2013 - 0.5.0: background operation using Location APIs. Downloads: 1011 AllCaps, 963 Normal
20 Jul 2014 - 0.5.1: More capabilities, better navigation. Downloads: 358 AllCaps, 352 normal
07 Aug 2014 - 0.5.3: .REG export, better traversal, bugfixes. Downloads as of 0.5.5 release: 260 AllCaps, 164 normal
10 Oct 2014 - 0.5.5: Bugfixes and back-end work. Downloads as of 0.6.0 release: 140 AllCaps, 113 normal
25 Oct 2014 - 0.5.6: Bugfixes and UI tweaks. Downloads as of 0.6.0 release: 1720 AllCaps, 1334 normal
12 Oct 2015 - 0.6.0: Binary requests, file uploads, bugfixes.
XDA:DevDB Information
WebServer Native Access, Tool/Utility for the Windows Phone 8 General
Contributors
GoodDayToDie
Source Code: https://wp8webserver.codeplex.com/
Version Information
Status: Alpha
Created 2014-10-17
Last Updated 2015-10-12
I'm going to use this space to mention something that's pretty cool:
J. Arturo of http://www.komodosoft.net is using a modified version of the HTTP server that powers this app in the ShareFolder app (http://www.windowsphone.com/s?appid=e2b9c82e-eaa1-4a3b-9d4a-8a2933a8bdb4) to support opening video files directly from Windows network shares! This was done to work around a limitation of the WP8 media control: it can only source from an isolated storage file or a HTTP URL. By running a server in the background and streaming the video file through it, and pointing the video player control at the localhost URL, it becomes possible to play the file on the phone without first copying it to the app's isolated storage. A very cool way to solve the problem! Also, reviewing the changes that were made to the network code of the server pointed me toward those threading fixes I made that have hopefully much improved version 0.4.9.
Please note that the updated version of ShareFolder with this feature may not yet be available, although it should be soon. It is a commercial (paid) app, but the author sought and received permission to use my code (although the license does not require such permission be received).
What exactly is the problem with sockets? I am battling myself with sockets atm too, maybe we can share knowledge?
Strictly speaking, the problem was with the phone's limited subset of the Sockets API forcing me to access it through functions I wouldn't normally use (asynchronous everything, SocketAsyncEventArgs and lambdas and AutoResetEvents and so on everywhere...) but I've got a pretty good handle on it now, at least for the System.Net.Sockets.Socket and its friends. The new .NET 4.x ones (using the async keyword and all) are in a different namespace; I didn't mess with them. They are more abstracted from the Bekeley sockets interface that I'm used to from C, but they are also (supposedly) more user-friendly, especially if you don't feel like writing all your own thread management code (and in fairness, I should re-write the webserver's threading to use threadpools; they're better for this type of work).
If you want to ask questions about the topic, I suggest starting a new thread (possibly in the Q&A subforum, although it's also dev related...) and I'll answer if I can.
GoodDayToDie, just an idea: how about sharing your source code via CodePlex or GitHub?
Oh man, this is pretty nice! GoodDayToDie does it again!
So far, I can read \Windows, the current install folder which you access just by typing "." with no quotes and the current application folder by typing ".." I can access the .dlls, .winmd and AppManifest.xml from the current install, but from everywhere else, it goes boom. This is a great step towards something awesome though!
EDIT:
I was wrong. For some reason, when you click on a folder it's trying to "download" it, rather than chdir. I can get pretty far into the Windows directory.
THAT's what you meant by "Click on a file (note: there's no current way to tell the difference between files and folders) to download it.
You might see an error code (error 5 is "ACCESS_DENIED", you'll see it a lot). Or you might see a status 500 message because of an exception in the server. It's getting a lot more resilient but there are surely still some bugs. ".
If you see a folder, just type the full path to it instead of clicking on it and you will be able to read the contents.
ANOTHER EDIT:
I just found a file inside of the \Windows\System32 directory named [guid].devicemetadata-ms (It's easier to just search for "devicemetadata-ms"). It's a cab file with some metadata about WP8 with a sign.cat and packagesign.cat file in the archive. I don't know what these files could potentially be useful for.
New version in a day or two (busy tonight). Features I plan to implement (not necessarily in the next version or at any particular time):
File upload (IsoStore and, of all crazy things, install directory are writable. I think I'll put a flag on each FS page that says whether the current dir is writable...).
File deletion (where possible, of course).
File and Directory distinction in the listing (clicking a dir should open it, not error out).
Filesystem index page with links to folders that can be accessed successfully (since the root isn't readable).
Some more file info (size, probably attributes, possibly permissions).
Possibly an option to preview a file (as plain text) without downloading it.
Some kind of background mode (the server uses minimal resources when not actively servicing a request, so I'll see if I can get it to work in the background, perhaps by abusing the music transfer agent...)
Some kind of offline mode (at least basic file browsing within the app, as an alternative to using the web interface, though I might just make a second app for that).
Source code changes: separate the server code from the webapp / phone app code (move it into its own project).
Source code changes: move to a hosted version control service, probably CodePlex (good suggestion sensboston).
Maybe add an icon and such...
Any other suggestions?
I also want to try experimenting with various non-standard capabilities and see if I can get access to more of the system . I've already added the ability to access removable storage, but I've also found a bunch of really weird and frequently undocumented capabilities in the OS's policy configuration files, and I need to look into those... The interesting (and possibly the uninteresting) ones are probably blocked for unsigned sideloaded apps, but it's worth checking on anyhow.
Yeah sorry, I should have been more explicit about clicking on dirs. not working in 0.2.0. Also, it's "unofficial" but if you check the URL bar you'll see a URL parameter called something like "pattern" (by default, it's *) and if you change that, you can filter the results. For example, "foo*.exe" (note: no quotes!) will search for EXE files whose names start with "foo". Among other uses, this makes it a lot faster to load large dirs like System32. This will be added to the UI at some point. Also note that URL decoding is applied correctly to querystring parameters (Probably already noticed with the path sometimes written using %5C for \) so you can add special characters that way if needed, though currently any of them but \ will probably just cause an exception.
...
Actually, does this filesystem support Alternate Data Streams? If so, you should be able to download them by appending a : and the ADS name to the filename in the download URL...
OK, so that was a new version in five days. Sorry, stuff takes time.
The source code is now on Codeplex. The native access portion is at https://wp8nativeaccess.codeplex.com/, and the web server portion is at https://wp8webserver.codeplex.com/. Both are licensed MS-PL and use Git for version control. The full XAP is also available for download from the Webserver project on Codeplex.
GoodDayToDie said:
OK, so that was a new version in five days. Sorry, stuff takes time.
The source code is now on Codeplex. The native access portion is at https://wp8nativeaccess.codeplex.com/, and the web server portion is at https://wp8webserver.codeplex.com/. Both are licensed MS-PL and use Git for version control. The full XAP is also available for download from the Webserver project on Codeplex.
Click to expand...
Click to collapse
You are a god. I'll be sure to post my findings .
Hmm. When I first load up WebServer File Access then access from my laptop, I get the main page then the program crashes on my phone. It seems to hold a lock on to the socket as i can no longer access port 9999 from any other device when re-opening the app. I can access it again when I reboot, but the same thing happens.
EDIT: I think it may be due to the WiFi at work... it's junky. I'll try again when I get home. I was just able to browse some directories.
Wow, that's completely unexpected... I can beef up the error chacking and handling around the listener port though. That part of the code is really straightforward, so I actually haven't hardened it very much. I can also put in a Finally block to close the socket and/or mark the socket as re-usable so that other apps (or the same one again) can listen on it in the future.
I also plan to add support for setting your own port, but that doesn't solve the underlying problem. I'll put in more error reporting as well, to enable better debugging. Thanks for the report! Always good to have users report problems so I know where to prioritize fixes.
GoodDayToDie said:
Wow, that's completely unexpected... I can beef up the error chacking and handling around the listener port though. That part of the code is really straightforward, so I actually haven't hardened it very much. I can also put in a Finally block to close the socket and/or mark the socket as re-usable so that other apps (or the same one again) can listen on it in the future.
I also plan to add support for setting your own port, but that doesn't solve the underlying problem. I'll put in more error reporting as well, to enable better debugging. Thanks for the report! Always good to have users report problems so I know where to prioritize fixes.
Click to expand...
Click to collapse
I tried the app at home and it DOES crash on the first hit of the home page, but I'm able to open it up again and it works fine.
The new version 0.3.3 should be more rebust; try it and let me know if you still have issues. If you do, let me know what the exception message is (and any other info you can provide) and I'll try to track it down.
Downloading really big files should also work now. The app will read and push files in smaller chunks (the code to do this existed in the NativeAccess library before, but wasn't used).
a simple SDK?
Dear Sir
Will it be possible for you to make some sort of SDK from this so other developers can integrate this into their apps and enable browsing isolatedstorage?
Sorry if it is a stupid question.
Bruce_X_Lee said:
Dear Sir
Will it be possible for you to make some sort of SDK from this so other developers can integrate this into their apps and enable browsing isolatedstorage?
Sorry if it is a stupid question.
Click to expand...
Click to collapse
With the restrictions in permissions, this app only allows browsing of the app's isolatedstorage locally. You are able to use the IsolatedStorage API within your app to browse files and directories already.
snickler said:
With the restrictions in permissions, this app only allows browsing of the app's isolatedstorage locally. You are able to use the IsolatedStorage API within your app to browse files and directories already.
Click to expand...
Click to collapse
That's right. What I want is to allow the end user to be able to browse the isolatedstorage. Imagine I have a video download app, I want the user to be able to transfer those downloaded videos from the app's isolated storage to, say, a PC.
One can do this by integrating the webserver code into the said app.
Bruce_X_Lee said:
That's right. What I want is to allow the end user to be able to browse the isolatedstorage. Imagine I have a video download app, I want the user to be able to transfer those downloaded videos from the app's isolated storage to, say, a PC.
One can do this by integrating the webserver code into the said app.
Click to expand...
Click to collapse
Ahh I see what you mean now. That sounds like a pretty nice idea. I think more research needs to be done to see whether it would even be allowed in the marketplace.
The webserver portion is stand-alone (builds to its own .NET DLL with no dependencies on the other parts) and has a pretty clean interface. You'd need to implement the web application portion of it yourself - the thing that generates the response pages for a given request - but the HttpResponse class in the server does a lot of the work of that for you; you basically just specify the content you want to send (as a String or byte array) and it sends it.

[LIBRARY / GUIDE] Remote Metadata Provider

Hello, my fellow XDAers.
Recentlly I've created a guide about how to implement your all lockscreen-like music controls.
However, the problem was that this way of implementing your remote music controls(let's call it this way, okay?) was extremely counter-intuitive.
Starting from methods which have bunch of setSomething but no getSomething and ending with weird Handler.Callback required.
So, in order to ease this process, I've created small library.
For the sake of simplicity, it's distributed as a JAR file, not as a library project.
Why?
The main reason is:
The library relies heavily on hidden interface IRemoteControlDisplay and hidden methods of AudioManager.
Accessing IRemoteControlDisplay even with reflection is IMPOSSIBLE, because that will require some tool to modify classes at runtime.
This is way too complex, so instead I use a modified android.jar with hidden classes exposed.
So, in order to use this library, you would have to download modified android.jar(or create it yourself), and create modified android platform for Eclipse...
Doesn't sound like fun, does it?
So, to prevent this, I've packaged my project as a library JAR.
Click to expand...
Click to collapse
That doesn't mean that my library is closed-source. It's completely open-sourced, and is available in form of ZIP archive or GitHub repository.
Also, it is licensed under Apache 2.0, so that means you can use it in any of your projects, commercial or not.
Just remember that instead of buying alcohol and junk food you can send me some little donation
Okay, end of introduction.
Now, off to the guide and download links.
The name of this library is:
Remote Metadata Provider​
This library allows you to create your own remote media controls, which will act the same as lockscreen controls.
This is achieved by usage of some Listeners and class called RemoteMetadataProvider.
1. Reference:
Class: RemoteMetadataProvider
Code:
[B]static synchronized RemoteMetadataProvider getInstance(Context context)[/B]
This method returns an instance of RemoteMetadataProvider.
Context is required to fetch instance of AudioManager and to send media button commands.
Also, it is used to retrieve launch Intent for current active client(player).
Please note that calling to this method from incorrect API version will result in RuntimeException.
remote-metadata-provider.jar is for API 17 and lower.
remote-metadata-provider-v18.jar is for API 18.
Code:
[B]void acquireRemoteControls()[/B]
This method makes current RemoteMetadataProvider active, so you will receive metadata updates.
You MUST call this method when View displaying your metadata becomes visible to the user(the sentence above explains, why).
Please note that only one RemoteMetadataProvider can be active at time.
Code:
[B]void dropRemoteControls(boolean destroyRemoteControls)[/B]
This method makes current RemoteMetadataProvider inactive.
You won't be receiving further metadata updates, and most likely you will lose control of current client.
This method MUST be called whenever your view displaying metadata becomes invisible to the user.
If you won't do so, then system can lose it's remote media controls or it can interfere with other apps.
Boolean defines, whenever remote media controls should be destroyed or not. If you have some problems with artwork not displaying in your app after dropping remote controls/acquiring it, when set this parameter to true, otherwise use false(it will save memory and time).
My tests shown that it will not interfere, but it's better to be safe and call this method.
Code:
[B]Intent getCurrentClientIntent()[/B]
This will return launch Intent for current player or null if there is no active clients.
It throws NameNotFoundException in case client package wasn't found.
This exception should not happen under normal circumstances - if it was thrown, then probably something bad happened with the system itself.
Code:
[B]PendingIntent getCurrentClientPendingIntent()[/B]
Returns PendingIntent of current client or null if there is no current client.
This method isn't used generally, but you can(for example) save PendingIntents of multiple players to re-use them in a future or to prevent fast client loss.
Code:
[B]Looper getLooper()[/B]
Returns user-defined Looper which is used if you are processing metadata in some special thread or null if default Looper is used.
Code:
[B]OnArtworkChangeListener getOnArtworkChangeListener()[/B]
Returns callback to be invoked when artwork has to be updated or null if there is no such callback..
Code:
[B]OnMetadataChangeListener getOnMetadataChangeListener()[/B]
Returns callback to be invoked when metadata has to be updated or null if there is no such callback.
Code:
[B]OnPlaybackStateChangeListener getOnPlaybackStateChangeListener()[/B]
Returns callback to be invoked when playback state has changed.
Code:
[B]OnRemoteControlFeaturesChangeListener getOnRemoteControlFlagsChangeListener()[/B]
Returns callback to be invoked when remote control features has changed.
Code:
[B]boolean isClientActive()[/B]
Returns true if there is active client which can send metadata and receive media commands and false otherwise.
Code:
[B]void removeLooper()[/B]
Tells the RemoteMetadataProvider to recreate Handler without Looper(if there was one) on next acquireRemoteControls() call.
Code:
[B]void sendBroadcastMediaCommand(int keyCode)[/B]
Sends media button input event with specified keycode(use KeyEvent class to get keycodes from there) in form of Broadcast message.
In most cases it will fail, but some players like Neutron Player and Poweramp are able to receive this broadcast message.
Do not use this method if you have active clients.
Use this method only if you don't have any active clients and you want to try to start client with broadcast message.
Code:
[B]void sendBroadcastMediaCommand(MediaCommand command) [/B]
The same as the method above, but you specify command as a MediaCommand enum.
Code:
[B]boolean sendMediaCommand(int keyCode)[/B]
This command will send media button input event to current active client.
It will return true if command was successfully delivery or false if it failed.
For example, if there is no active clients, it will return false.
Code:
[B]boolean sendMediaCommand(MediaCommand command)[/B]
The same as the method above, but instead it uses MediaCommand enum to specify media button input event.
Code:
[B]void setCurrentClientPendingIntent(PendingIntent pintent)[/B]
Sets current client PendingIntent to one specified by you. Do not use it unless you received PendingIntent via getCurrentClientPendingIntent().
Code:
[B]void setLooper(Looper looper)[/B]
Sets Looper for processing the metadata receiving in another thread. Call acquireRemoteControls() to start using this Looper.
Code:
[B]void setOnArtworkChangeListener(OnArtworkChangeListener l)[/B]
Register a callback to be invoked when artwork should be updated.
Code:
[B]void setOnMetadataChangeListener(OnMetadataChangeListener l)[/B]
Register a callback to be invoked when metadata should be updated.
Code:
[B]setOnPlaybackStateChangeListener(OnPlaybackStateChangeListener l)[/B]
Register a callback to be invoked when playback state should be updated.
Code:
[B]setOnRemoteControlFeaturesChangeListener(OnRemoteControlFeaturesChangeListener l)[/B]
Register a callback to be invoked when remote control features should be updated.
Interface: OnArtworkChangeListener
Code:
[B]void onArtworkChanged(Bitmap artwork)[/B]
Called when artwork of current song album was updated.
artwork parameter is a Bitmap containing current artwork. May be null if it wasn't specified by player.
Please note that previous Bitmap is recycled after artwork update! So don't forget to use Bitmap#isRecycled() if you're saving album arts somehow.
Interface: OnMetadataChangeListener
Code:
[B]void onMetadataChanged(String artist, String title, String album, String albumArtist, long duration)[/B]
Called when remote metadata was updated.
Parameter artist is the artist of current song. May be null if wasn't specified by player. Some players use albumArtist parameter instead.
Parameter title is the title of current song. May be null if wasn't specified by player.
Parameter album is the current song album title. May be null if wasn't specified by player.
Parameter albumArtist is the current song album artist. May be null if wasn't specified by player. Some players(for example, PowerAmp) use this parameter instead of artist parameter.
Parameter duration is the song duration in milliseconds.
Interface: OnPlaybackStateChangeListener
Code:
[B]void onPlaybackStateChanged(PlayState playbackState)[/B]
Called when playback state was changed. For example, this method will be called with parameter PlayState.PAUSED
when playback is paused.
Possible values of playbackState parameters are listed in enum class PlayState.
Interface: OnRemoteControlFeaturesChangeListener
Code:
[B]void onFeaturesChanged(List<RemoteControlFeature> usesFeatures)[/B]
Called when information about player was changed.
usesFeatures is a list containing different RemoteControlFeature enums. This list describes, to which
buttons the player will respond correctly.
For example, if this list contains RemoteControlFeature.USES_REWIND, then the player would respond to Rewind command.
Enum: MediaCommand
Code:
NEXT - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to jump to next track.
PREVIOUS - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to jump to previous track.
PLAY - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to start playback. Usually it is treated the same as PLAY_PAUSE.
PAUSE - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to pause playback. Usually it is treated the same as PLAY_PAUSE.
PLAY_PAUSE - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to pause the track if it was playing and to start it if it was paused.
REWIND - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to rewind the song.
FAST_FORWARD - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to fast forward the song.
STOP - use this constant with RemoteMetadataProvider#sendMediaCommand(MediaCommand) to tell the player to stop playback.
Enum: RemoteControlFeature
Code:
USES_FAST_FORWARD - indicates that player makes use of Fast Forward button.
USES_NEXT - indicates that player makes use of Next button.
USES_PAUSE - indicates that player makes use of Pause button.
USES_PLAY - indicates that player makes use of Play button.
USES_PLAY_PAUSE - indicates that player makes use of Play button.
USES_PREVIOUS - indicates that player makes use of Previous button.
USES_REWIND - indicates that player makes use of Rewind button.
USES_STOP - indicates that player makes use of Stop button.
Enum: PlayState
Code:
BUFFERING - the music is buffering right now and should start playing soon.
ERROR - some error occured. We should not except the music to start playing.
FAST_FORWARDING - the music is being fast forwarded.
PAUSED - the music is paused.
PLAYING - the music is playing.
REWINDING - the music is being rewinded.
SKIPPING_BACKWARDS - the music is being skipped backwards.
SKIPPING_FORWARDS - the music is being skipped forwards.
STOPPED - the music is stopped.
1a. Reference for API 18 version of library:
Only the differences will be listed here. If method/interface/enum is not listed here, then it's the same as in pre-API 18 version of library.
Class: RemoteMetadataProvider
Code:
[B]void acquireRemoteControls()[/B]
This method makes current RemoteMetadataProvider active, so you will receive metadata updates.
You MUST call this method when View displaying your metadata becomes visible to the user(the sentence above explains, why).
Multiple RemoteMetadataProviders can be active at the time.
Use this method if you DO NOT NEED artwork updates.
Code:
[B]void acquireRemoteControls(int maxWidth, int maxHeight)[/B]
This method makes current RemoteMetadataProvider active, so you will receive metadata updates.
You MUST call this method when View displaying your metadata becomes visible to the user(the sentence above explains, why).
Multiple RemoteMetadataProviders can be active at the time.
Use this method if you NEED artwork updates.
Parameter maxWidth is maximum width of Bitmap artwork which you will receive.
Parameter maxHeight is maximum height of Bitmap artwork which you will receive.
Code:
[B]void setPlaybackPositionSyncEnabled(boolean isEnabled)[/B]
Sets state of playback position update. If you pass true to this method, then you will receive position updates by OnPlaybackStateChangeListener callback. If you set false, you will not receive position updates.
Please note that this method have to be called ONLY after calling acquireRemoteControls() method, or it will fail.
Interface: OnPlaybackStateChangeListener
Code:
[B]onPlaybackStateChanged(PlayState playbackState, long playbackPosition, float speed)[/B]
Called when playback state, playback speed or playback position was changed.
For example, this method will be called with parameter PlayState.PAUSED
when playback is paused.
Possible values of playbackState parameters are listed in enum class PlayState.
Parameter playbackPosition is current playbackPosition is playback position in ms.
Please note that for this parameter to be updated you have to call RemoteMetadataProvider#setPlaybackPositionSyncEnabled(true) first.
Parameter speed is current playback speed. Normal playback speed is 1.0f, 2x is 2.0f etc.
Enum: RemoteMetadataFeature
Code:
Everything is same, except for this three new parameters:
USES_POSITIONING - it indicates that current player will send you position updates.
USES_WRITABLE_POSITIONING - currently not used, added for future. Indicates that player should respond to remote position update.
USES_READABLE_POSITIONING - probably not used too. Indicates that player should tell you it's playback position.
2. How to use:
Usage of my library is extremely simple. First of all, add my library to your project as an external JAR.
Then do the following steps:
1) Get the instance of RemoteMetadataProvider with RemoteMetadataProvider.getInstance(context). Remember, this is a singleton, so all getInstance calls will return the same instance. To save time, save it in field variable, let's call it mProvider.
2) Implement necessary listeners and register them. For example, you want to receive metadata updates and you want to show them in TextViews. Then you can use following code.
Code:
mProvider.setOnMetadataChangeListener(new OnMetadataChangeListener() {
[user=439709]@override[/user]
public void onMetadataChanged(String artist, String title, String album, String albumArtist, long duration) {
mArtistTextView.setText("ARTIST: "+artist);
mTitleTextView.setText("TITLE: "+title);
mAlbumTextView.setText("ALBUM: "+album);
mAlbumArtistTextView.setText("ALBUM ARTIST: "+albumArtist);
mDurationTextView.setText("DURATION: "+(duration/1000)+"s");
}
});
Other listeners are registered in same manner. Read reference to get the details.
3) When your view with current metadata is displayed, call mProvider.acquireRemoteControls(). For example, if you're displaying metadata in Activity, you should call this method in your onResume() method.
3) When your view is hidden, you should call mProvider.dropRemoteControls(boolean). Generally, the parameter should be false, but there are some cases when artwork isn't being displayed after calling dropRemoteControls() and then acquireRemoteControls(). So, if there are problems with artwork, use true as a parameter.
4) To tell player to do something with playback, use mProvider.sendMediaCommand(MediaCommand).
This method will return true if the command was delivered successfully and false otherwise.
For example, you can use following code to make button with id "next" work as a Next button:
Code:
findViewById(R.id.next).setOnClickListener(new OnClickListener() {
[user=439709]@override[/user]
public void onClick(View v) {
if(!mProvider.sendMediaCommand(MediaCommand.NEXT)) {
Toast.makeText(getApplicationContext(), "Failed to send NEXT_EVENT", Toast.LENGTH_SHORT).show();
}
}
});
This will send NEXT command to player, or will display toast message with error text if there is no active player.
5) If there is no current player, but you know that there is some player which can receive Broadcast media event, you can use
mProvider.sendBroadcastMediaCommand(MediaCommand).
For example, following code can be used to make button with id "next" send Broadcast command on long click.
Code:
findViewById(R.id.next).setOnLongClickListener(new OnLongClickListener() {
[user=439709]@override[/user]
public boolean onLongClick(View v) {
mProvider.sendBroadcastMediaCommand(MediaCommand.NEXT);
return true;
}
});
Basically, that's all you need.
3. Licensing
This project is licensed under Apache 2.0 license.
4. Source code
GitHub link: https://github.com/DrBreen/RemoteMetadataProvider
Source codes for library and test application are available at the end of the post.
5. Bugs
-On HTC Sense the system will lose lockscreen controls after calling RemoteMetadataProvider#acquireRemoteControls().
This is due to how the lockscreen is being initialized on HTC Sense, and it can't be fixed unless I'll do deep investigation of decompiled source code and write Xposed module which will somehow re-register original system metadata receiver.
Files with "v18" suffix are for Android 4.3. Without this suffix - for Android 4.2.2 and lower.
Please do not cross-use this libraries, or you will get RuntimeException(in getInstance() method) or AbstractMethodError(if you somehow acquire instance of the RemoteMetadataProvider without calling getInstance()).
Nice job. :good:
Added library and source codes for Android 4.3.
I an getting the following error in the "exported" version of the apk, but not in the debug compiled version.
09-25 07:25:56.112: E/JavaBinder(24862): java.lang.AbstractMethodError: abstract method not implemented
09-25 07:25:56.112: E/JavaBinder(24862): at android.media.IRemoteControlDisplay$Stub.setCurrentClientId(IRemoteControlDisplay.java)
09-25 07:25:56.112: E/JavaBinder(24862): at android.media.IRemoteControlDisplay$Stub.onTransact(IRemoteControlDisplay.java:65)
09-25 07:25:56.112: E/JavaBinder(24862): at android.os.Binder.execTransact(Binder.java:367)
09-25 07:25:56.112: E/JavaBinder(24862): at dalvik.system.NativeStart.run(Native Method)
09-25 07:25:56.112: W/dalvikvm(24862): threadid=8: thread exiting with uncaught exception (group=0x41d3b2a0)
09-25 07:25:56.112: E/android.os.Debug(2243): [email protected] > dumpstate -k -t -z -d -o /data/log/dumpstate_app_error
09-25 07:25:56.112: E/AndroidRuntime(24862): FATAL EXCEPTION: Binder_1
09-25 07:25:56.112: E/AndroidRuntime(24862): java.lang.AbstractMethodError: abstract method not implemented
09-25 07:25:56.112: E/AndroidRuntime(24862): at android.media.IRemoteControlDisplay$Stub.setCurrentClientId(IRemoteControlDisplay.java)
09-25 07:25:56.112: E/AndroidRuntime(24862): at android.media.IRemoteControlDisplay$Stub.onTransact(IRemoteControlDisplay.java:65)
09-25 07:25:56.112: E/AndroidRuntime(24862): at android.os.Binder.execTransact(Binder.java:367)
09-25 07:25:56.112: E/AndroidRuntime(24862): at dalvik.system.NativeStart.run(Native Method)
Click to expand...
Click to collapse
I have added the following lines in proguard to make the warnings go away.
-dontwarn android.media.IRemoteControlDisplay$Stub
-dontwarn android.media.IRemoteControlDisplay
-dontwarn android.media.AudioManager
Click to expand...
Click to collapse
Any idea why this is happening?
spadival said:
I an getting the following error in the "exported" version of the apk, but not in the debug compiled version.
I have added the following lines in proguard to make the warnings go away.
Any idea why this is happening?
Click to expand...
Click to collapse
I think that's because of wrong versioning. It looks like you somehow use the 4.2.2 version for 4.3 or the other way.
Dr.Alexander_Breen said:
Files with "v18" suffix are for Android 4.3. Without this suffix - for Android 4.2.2 and lower.
Please do not cross-use this libraries, or you will get RuntimeException(in getInstance() method) or AbstractMethodError(if you somehow acquire instance of the RemoteMetadataProvider without calling getInstance()).
Click to expand...
Click to collapse
So I take it this means that if I wanted to implement this in an application designed to run on API 14+ (including KitKat and beyond) I'll have to use the guide and do it manually. Am I correct?
At first, thank you for this awesome Lib!
It is working very well on 4.2.2 CM.
But on 4.4 (Nexus 7 2013) and 4.1.2 (S3 stock) I am not able to read the playback state. Any idea?
Edit: The next and previous button on 4.4 Nex and 4.1.2 s3 is working well. It is just the playback state..
Edit2: On your floating music widget it is not working, too :/
Edit3: setOnPlaybackStateChangeListener and setOnMetadataChangeListener seem not to work with 4.4
Thanks
WisdomWolf said:
So I take it this means that if I wanted to implement this in an application designed to run on API 14+ (including KitKat and beyond) I'll have to use the guide and do it manually. Am I correct?
Click to expand...
Click to collapse
Well, on KitKat there is a class called RemoteController, which has the same functionality, so you does not need to use this library on API 19+.
v18 library is designed to run only on API 18.
"Normal" version should run fine of API 14, 15, 16, 17.
Okay. Thanks for the reply.
I used now intentfilter with the ending "playstatechanged". With this action the music apps sends the extra "playing" ture/false.
I tested it with s3 music player and google play music on nexus 7. Worked fine. Just the huawei music player is not working.
Edit: Your apps just need an update right now to make them working with 4.3 / 4.4?
On 4.3 your apps should work but on samsung s3 with 4.3 it is not working well with the stock music player. Just as information
Anyway good library
KitKat
Anyone please give tutorial how does RemoteController works on kitkat :/
Dr.Alexander_Breen said:
Well, on KitKat there is a class called RemoteController, which has the same functionality, so you does not need to use this library on API 19+.
v18 library is designed to run only on API 18.
"Normal" version should run fine of API 14, 15, 16, 17.
Click to expand...
Click to collapse
What's wrong with creating a unified library that will work across API 14-18?
WisdomWolf said:
What's wrong with creating a unified library that will work across API 14-18?
Click to expand...
Click to collapse
There's nothing wrong. It just was that I didn't have an idea how to unite them because of conflicting IRemoteControlDisplay.aidl file which has to be in the same package with same name, yet different for different versions. Now I've understood how to combine it, so I'm currently working on RemoteControllerCompat, which will bring unified library usage across all API beginning from ICS(V14).
Oh, OK. I could probably submit a pull request as I've already managed to combine them. Or you can find my fork of your repo on Github.
EDIT: I sent you a pull request. Also, posting my modified version of your RemoteMediaTest application that works with ICS, JB, and KK's RemoteController class.
https://github.com/WisdomWolf/TESTRemoteMedia
Great work!!!
You are bloody awesome mate. You have done a marvelous job with this library. I cannot thank you enough. I am just getting started with Android development, was stuck at those internal and hidden classes. For some reason eclipse would force close after modifying the ADT plugin. That's when i stumbled upon your thread. Thanks a ton once again. You Rock!! :good:
Here is the guide for the RemoteController:
[GUIDE] Implement RemoteController in your app
I am thoroughly stumped. Do you have any suggestions for using RemoteController in an application that is also designed to handle notifications and be backwards compatible with 4.3? The odd requirement to inherit NotificationListener really throws a wrench in things. I know I could actually define two different notification listeners but that seems inefficient and there's got to be a better way.
WisdomWolf said:
I am thoroughly stumped. Do you have any suggestions for using RemoteController in an application that is also designed to handle notifications and be backwards compatible with 4.3? The odd requirement to inherit NotificationListener really throws a wrench in things. I know I could actually define two different notification listeners but that seems inefficient and there's got to be a better way.
Click to expand...
Click to collapse
We probably could use reflection to register the guts of RemoteController directly to AudioService, bypassing the NotificationListener check. I suppose it's possible, but it can have unknown side effects. Do you want me to try it out, or you can do it yourself?
I have very little experience with using reflection, so your help would be greatly appreciated. I've tried all sorts of workarounds, but the registration always fails. The only other solution that I could think of was writing a dummy OnClientUpdateListener interface to be loaded when running API level 18. Not entirely sure how to accomplish that either though, but I believe it's something that could be accomplished by making use of ClassLoader. Any help you can offer would be very welcome. I'd still be trying to wrap my head around metadata if it weren't for your library and articles.
I figured it out. Your tip about reflection was really useful, but after chasing my tail for a bit I discovered that reflection wasn't necessary. I used the source code to find out exactly how the permission access was granted. It looks like it takes the OnClientUpdateListener from the RemoteController that gets passed to it and then checks the class against the enabled notificationlisteners. Once I realized that, I simply rewrote the registerRemoteController method to try getClass().getEnclosingClass() first. The registration bypasses the AudioManager, but all the other method calls are left in tact.
You setup a great example of a support library, so I used that concept to create a support library for KitKat's RemoteController class. It includes the modified registration method along with some passthroughs to otherwise inaccessible methods like getArtworkSize() and getRemoteControlClientPackageName(). I don't know if I'll have time to write a guide, but I've included the library in case anyone else is interested. You can find the source on my github.
Thanks a bunch for the library Dr. Alexander! It works pretty good and has saved me on a project that I'm currently working on.
...but I still have seen an issue or two. Namely, Samsung's default player that comes with its TouchWiz devices seems to not work want to work here. On a Galaxy S3 and S4 the default music player refuses to work with your library. However, other music apps on the phone do work (like Pandora and Rdio).
I'm guessing that this is not an issue that you can truly fix, given the nature of all of this. But I'm just hoping that maybe, just maybe, there's a chance.
Thanks mister, you've done a great job. And without your RemoteController guide, I would have never gotten that working either.

[GUIDE] Implement RemoteController in your app

Hello, fellow XDA-ers.
Today I want to tell you about new RemoteController class introduced in Android 4.4.
What does this class do?
The RemoteController class is used to control media playback, display and update media metadata and playback status, published by applications using the RemoteControlClient class.
Click to expand...
Click to collapse
However, the documentation is rather empty. Sure, there are methods etc., but it's not really helpful if you have zero knowledge about this class and you want to implement it right away.
So, here I am to help you.
Sit down and get your IDE and a cup of coffee/tea ready.
WARNING: This guide is oriented at experienced Android developers. So, I'll cover the main points, but don't expect me to go into details of something which is not directly related to RemoteController.
1. Creating a service to control media playback.
To avoid illegal access to metadata and media playback, user have to activate a specific NotificationListenerService in Security settings.
As a developer, you have to implement one.
Requirements for this service:
1. Has to extend NotificationListenerService[/B
2. Has to implement RemoteController.OnClientUpdateListener.
You can look at my implementation on GitHub.
Let's now talk about details.
It's better to leave onNotificationPosted and onNotificationRemoved empty if you don't plan to actually process notifications in your app; otherwise you know what to do.
Now we need to register this service in AndroidManifest.xml.
Add the following to the manifest(replacing <service-package> with actual package where your service lies, and <service-name> with your Service class name):
Code:
<service
android:name="<service-package>.<service-name>"
android:label="@string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
Please note: do not override onBind() method, as it will break the functionality of the service.
"service_name" is a name for your service which will be shown in Security->Notification access.
2. Handling client update events.
Now on to implementation of RemoteController.OnClientUpdateListener. .
You may process everything inside this service, or (which I consider a better alternative, as it gives more flexibility, and you can re-use your service for different apps) re-call methods of external callback to process the client update events.
Here, however, we will only talk about the methods and which parameters are passed to them.
The official description is good enough and I recommend reading it before processing further.
Code:
[B]onClientChange(boolean clearing)[/B]
Pretty self-explanatory. "true" will be passed if metadata has to be cleared as there is no valid RemoteControlClient, "false" otherwise.
Code:
[B]onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor)[/B]
[I]metadataEditor[/I] is a container which has all the available metadata.
How to access it? Very simple.
For text data, you use RemoteController.MetadataEditor#getString(int key, String defaultValue);
"R.string.unknown" is a reference to String resource with name "unknown", which will be used to replace missing metadata.
To get artist name as a String, use:
[B]metadataEditor.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, getString(R.string.unknown))[/B]
To get title of the song as a String, use:
[B]metadataEditor.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getString(R.string.unknown))[/B]
To get the duration of the song as a long, use:
[B]metadataEditor.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION, 1)[/B]
1 is the default duration of the song to be used in case the duration is unknown.
To get the artwork as a Bitmap, use:
[B]metadataEditor.getBitmap(RemoteController.MetadataEditor.BITMAP_KEY_ARTWORK, null)[/B]
"null" is the default value for the artwork. You may use some placeholder image, however.
And here is one pitfall.
Naturally, you would expect artist name to be saved with the key MediaMetadataRetriever.METADATA_KEY_ARTIST.
However, some players, like PowerAmp, save it with key MediaMetadataRetriever.METADATA_KEY_ALBUMARTIS.
So, to avoid unnecessary checks, you may use the following(returns String):
[B]mArtistText.setText(editor.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, editor.getString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, getString(R.string.unknown))));[/B]
What does it do - it tries to get the artist name by the key METADATA_KEY_ARTIST, and if there is no such String with this key, it will fall back to default value, which, in turn, will try to get the artist name by the key METADATA_KEY_ALBUMARTIST, and if it fails again, it falls back to "unknown" String resource.
So, you may fetch the metadata using these methods and then process it as you like.
Code:
[B]onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, long currentPosMs, float speed)[/B]
Called when the state of the player has changed.
Right now this method is not called, probably due to bug.
[I]state[/I] - playstate of player. Read the [URL="http://developer.android.com/reference/android/media/RemoteControlClient.html"]RemoteControllerClient class description[/URL] to get the list of available playstates.
For example, RemoteControlClient.PLAYSTATE_PLAYING means that music is currently playing.
[I]stateChangeTimeMs[/I] - the system time at which the change happened.
[I]currentPosMs[/I] - current playback position in milliseconds.
[I]speed[/I] - a speed at which playback occurs. 1.0f is normal playback, 2.0f is 2x-speeded playback, 0.5f is 0.5x-speeded playback etc.
Code:
[B]onClientPlaybackStateUpdate (int state)
[I]state[/I] - playstate of player. Read the [URL="http://developer.android.com/reference/android/media/RemoteControlClient.html"]RemoteControllerClient class description[/URL] to get the list of available playstates.[/B]
Code:
[B]onClientTransportControlUpdate (int transportControlFlags)[/B]
[I]transportControlFlags[/I] - player capabilities in form of bitmask.
This is one interesting method. It reports the capabilities of current player in form of bitmask.
Let's say, for example, you want to know if current player supports "fast forward" media key.
Here is how to do it:
[B]if(transportControlFlags & RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD != 0) doSomethingIfSupport(); else doSomethingIfDoesNotSupport(); [/B]
All of the flags are listed in [URL="http://developer.android.com/reference/android/media/RemoteControlClient.html"]RemoteControlClient class description.[/URL]
3. Creating RemoteController object.
The preparations are finished.
Now we need to construct RemoteController object.
The constructor of RemoteController takes two arguments. First is Context, and second is RemoteController.OnClientUpdateListener.
You should know how to fetch Context already.
Now let's talk about the second parameter. You have to pass YOUR SERVICE implementing RemoteController.OnClientUpdateListener and extending NotificationListenerService. This is a must, otherwise you won't be able to register your RemoteController to the system.
So, in your service, use something like this:
Code:
public class RemoteControlService extends NotificationListenerService implements RemoteController.OnClientUpdateListener {
private RemoteController mRemoteController;
private Context mContext;
...
@Override
public void onCreate() {
mContext = getApplicationContext();
mRemoteController = new RemoteController(mContext, this);
}
...
Now to activate our RemoteController we have to register it using AudioManager.
Please note that AudioManager#registerRemoteController returns "true" in case the registration was successful, and "false" otherwise.
When can it return "false"? I know only two cases:
1. You have not activated your NotificationListenerService in Security -> Notification Access.
2. Your RemoteController.OnClientUpdateListener implementation is not a class extending NotificationListenerService.
Code:
if(!((AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE)).registerRemoteController(mRemoteController)) {
//handle registration failure
} else {
mRemoteController.setArtworkConfiguration(BITMAP_WIDTH, BITMAP_HEIGHT);
setSynchronizationMode(mRemoteController, RemoteController.POSITION_SYNCHRONIZATION_CHECK);
}
Of course, we will have to deactivate RemoteController at some point with this code.
Code:
((AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE)).unregisterRemoteController(mRemoteController);
By default you will NOT receive artwork updates.
To receive artwork, call setArtworkConfiguration (int, int). First argument is width of the artwork, and second is the height of the artwork.
Please note that this method can fail, so check if it returns true or false.
To stop receiving artwork, call clearArtworkConfiguration().
4. Controlling media playback.
We can send media key events to RemoteControlClient.
Also, we can change position of playback for players which support it(currently only Google Play Music supports it).
You can send key events using this helper method:
Code:
private boolean sendKeyEvent(int keyCode) {
//send "down" and "up" keyevents.
KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
boolean first = mRemoteController.sendMediaKeyEvent(keyEvent);
keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
boolean second = mRemoteController.sendMediaKeyEvent(keyEvent);
return first && second; //if both clicks were delivered successfully
}
"keyCode" is the code of the pressed media button. For example, sending KeyEvent.KEYCODE_MEDIA_NEXT will cause the player to change track to next. Note that we send both "down" event and "up" method - without that it will get stuck after first command.
To seek to some position in current song, use RemoteController#seekTo(long). The parameter is the position in the song in milliseconds.
Please note that it will have no effect if the player does not support remote position control.
5. Getting current position.
RIght now the onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, long currentPosMs, float speed) method is broken, as it's not called when the position is updated. So, you have to manually fetch current position. To do this, use the RemoteController#getEstimatedMediaPosition() method - it returns current position in milliseconds(or other values, like 0, if player does not support position update).
To update it periodically, you may use Handler and Runnable. Look at the implementation on GitHub as the reference.
Hi. Good tutorial! How can i use RemoteController without MediaPlayer class? I'm using custom engine for playback.
XDA is usually pretty shi tty so I never come on here, and hence I had to reset my password to say thank you! This was really useful.
Including this code in NotificationListener Service on 4.3
Thank you for taking the time to describe the implementation in such detail. My only problem now is including implements RemoteController.OnClientUpdateListener in my NotificationListener class for an app that supports 4.0+. As soon as this service is started up by a 4.3 device the app crashes (reason is obvious, 4.3 doesn't support remote controller). The only solution I've found is to create 2 seperate notification listener classes, one for 4.3 and one for 4.4 (which has the RemoteController code in it). This also creates 2 entries in Notification Access list in the security settings.
Any ideas on how to make a hybrid service for 4.3/4.4 that implements the necessary RemoteController code?
corrytrevor said:
Thank you for taking the time to describe the implementation in such detail. My only problem now is including implements RemoteController.OnClientUpdateListener in my NotificationListener class for an app that supports 4.0+. As soon as this service is started up by a 4.3 device the app crashes (reason is obvious, 4.3 doesn't support remote controller). The only solution I've found is to create 2 seperate notification listener classes, one for 4.3 and one for 4.4 (which has the RemoteController code in it). This also creates 2 entries in Notification Access list in the security settings.
Any ideas on how to make a hybrid service for 4.3/4.4 that implements the necessary RemoteController code?
Click to expand...
Click to collapse
I have the exact same problem. Been searching for hours now, but I just couldn't come up with a solution for that issue.
Does anybody know how to solve this? Any kind of hint would be highly appreciated!
corrytrevor said:
Thank you for taking the time to describe the implementation in such detail. My only problem now is including implements RemoteController.OnClientUpdateListener in my NotificationListener class for an app that supports 4.0+. As soon as this service is started up by a 4.3 device the app crashes (reason is obvious, 4.3 doesn't support remote controller). The only solution I've found is to create 2 seperate notification listener classes, one for 4.3 and one for 4.4 (which has the RemoteController code in it). This also creates 2 entries in Notification Access list in the security settings.
Any ideas on how to make a hybrid service for 4.3/4.4 that implements the necessary RemoteController code?
Click to expand...
Click to collapse
I found a solution to this problem (or rather WisdomWolf did). http://stackoverflow.com/questions/...motecontroller-onclientupdatelistener-crashes
Problem solved
Finding music to play
Hi Thanks for the fantastic tutorial! Is there away to find a receiver if there is no music playing. I have noticed the line
Code:
I/RemoteController﹕ No-op when sending key click, no receiver right now
is logged. Thanks
Thanks for the great tutorial, very helpful for my current project. RemoteController is also used in KitKat built-in Keyguard KeyguardTransportControlView to replace RDC in older version.
ATI-ERP expeditious Business Solutions
Great article on building Remotecontroller in an Android application.
For More Android Apps visit ati-erp.com
ATI-ERP
i can't bind the service, i debug and seemd android start the service well , however trying bind the service onStart seems does not work in 4.4.4 someone has this issue? i tried reboot and other options
Nevermind i forgot to put the intent filter on manifest (shame on me)
Sorry to drag up an old thread. Does anyone know how to get the package of the client that is currently connected to / updating the RemoteController? I can't find it anywhere...

Categories

Resources