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.
So the end goal in this project is to view an RTMP stream and interact with the server at the same time.
This is a little hard, because obviously VLC or Mx Player or whatever I'm viewing the RTMP stream with doesn't know how to communicate with the custom server. So I'm trying to make an overlay that will sit on top of the player which has buttons, the buttons can then communicate with the server which will alter the stream and you'll see the result streamed to the player. This is sort of like an interactive HUD if you will.
Problem is that it's difficult to make an overlay which will take actions if they're clicked, but can also pass those actions to the background app (in this case the player) if it opts not to process them. Right now my app creates a service and the service catches the input and displays whatever. This WORKS, but the problem is no matter what I return from "onTouchEvent(MotionEvent)" in the view of the service (true or false) the home screen is frozen. It catches the press but it won't pass it on, even if the function returns "false" - to say it's not handled.
I'm not sure if I'm not passing the touch event on correctly, or is this not even possible? I read somewhere that it's not possible for app A to provide input to app B, but I'm not sure if that is correct (frankly I don't believe it). Basically I want to handle some presses in the overlay and allow some others to go to the active app beneath it.
Does anybody have any input for making this work as expected? I'm creating a view to pass to the window manager with the following flags:
Code:
LayoutParams params = new LayoutParams(LayoutParams.TYPE_SYSTEM_ALERT,
LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
I've tried playing with the flags but to no avail, I cannot get the touches to go through, even if all the onTouchEvent(MotionEvent) function does is return false.
Anybody have any ideas?
I'd be open to alternative implementation ideas too, the point is I need to basically have two communication channels open, one is a player (ie. VLC) for viewing the RTMP stream, which likely would not change, the other would be the command stream, which will control said server, which I am open to change. I considered trying to use the accelerometer in the service instead of an overlay, but I think that would create a bad proof of concept UI (because there's some latency in the video stream), any alternative ways to communicate with the server would be up for discussion! Maybe I can plug an IO device into the USB port or something, like a keyboard? Extra buttons could be of use. It's only a POC, so some clunkyness IS okay.
EDIT:
As you can see above, I used an alert type instead of an overlay type, I guess this is because overlays won't accept focus after a certain Android version number. I'm using 4.0.4 ICS.