Apk mirror websites prevention - Java for Android App Development

Hello everyone! I have a somewhat broad question(s) that I have some concerns about.
A recent search on the web revealed that many, if not all, of my apps published on Google Play are also being hosted on many, many apk mirror websites (such as ApkMania.com, or something like that along with PAGES of others). I like to stictly stick to Google Play for the distribution of my apps, and have not opted-in to distributing with 3rd parties, nor sharing my apps with anyone other than Google Play.
So my concerns/questions begin:
1) all of my apps are free, but have ads included in them so I can make a tiny bit of money from my hard work. Is it possible, or even more specifically, likely that my apps are being "hacked" or reverse-engineered to change the developer advertisement ID in which someone else would be getting revenue for my work? My apps are obfuscated so I'm sure it wouldn't be easy, but definitely not impossible.
2) I will begin checking the installer package name of my apps to make sure it is downloaded from Google Play. If it hasn't been, then the app(s) will show a dialog informing the user to download from Google Play, and close the app. Is there anything more that I can do to prevent this unwanted hosting?
3) Besides the above-mentioned, is there anything else I should be worried about?
I apologize if this is in the wrong section or is something I shouldn't be too concerned about, but I want my apps to ONLY be distributed through Google Play and was pretty frustrated when I found out that there were so many websites hosting my app. They would let you download directly from their website. If they redirected to Google Play, sure no problem. This is not the case :/
I would be much more concerned it these apps weren't free. I know this kind of stuff is bound to happen, but I would like to prevent/minimize it as much as possible.
Thank you for reading and your time. Any and all insight is appreciated. Cheers!

I haven't published an app yet and hopefully will publish one next month..
It is scary to read your experience.. do share anything you come across to minimize these things you have mentioned.. ( I would too if I see any article on this)
I will begin checking the installer package name of my apps to make sure it is downloaded from Google Play. If it hasn't been, then the app(s) will show a dialog informing the user to download from Google Play, and close the app
Click to expand...
Click to collapse
can you give a code example to do this?

ASIC SP said:
I haven't published an app yet and hopefully will publish one next month..
It is scary to read your experience.. do share anything you come across to minimize these things you have mentioned.. ( I would too if I see any article on this)
can you give a code example to do this?
Click to expand...
Click to collapse
I currently have 5 apps on the market (1st one was published in 2012) and have been learning on my own for about 4-5 years now, and just realized this unwanted hosting. It is a bit frightening in a way, but others have told me its "free hosting/marketing". I disagree since I opted out of 3rd party distribution. I know this stuff happens as with any other kind of digital goods though.
I am about to make a dialog class that will be easily put into any application that will do the above-mentioned (instruct the user to download from Google Play and close application) and will provide it here when it is complete It should be done in an hour or so, or at latest, tomorrow about the same time if I run into problems for some reason.
I wouldn't worry too much, just make sure you use proguard to obfuscate your code. There is documentation on the android developer website if you have questions about that. When/if you publish your app on Google Play, also opt-out of 3rd party marketing/distribution (if you so desire, it is with Google affiliates).
I'll post here again soon. Until then, happy coding!

Alright, it took a little longer than I anticipated, but this is satisfactory for my needs, simple yet effective.
@ASIC SP in your main activity, or Launcher activity (the one that starts when the application is opened)
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final PackageManager pckManager = getPackageManager();
ApplicationInfo appInfo = null;
try {
appInfo = pckManager.getApplicationInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
// Check if your app was installed by Google Play
if (!"com.android.vending".equals(pckManager.getInstallerPackageName(appInfo.packageName))) {
//App was not installed by Google Play
// Create TextView with link
final TextView tvMessage = new TextView(this);
tvMessage.setText(R.string.dialog_message);
tvMessage.setMovementMethod(LinkMovementMethod.getInstance());
tvMessage.setGravity(Gravity.CENTER);
final AlertDialog alertDialog = new AlertDialog.Builder(this)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Finish/close the activity when dialog is closed
finish();
}
})
.setTitle(getResources().getString(R.string.dialog_title))
.setView(tvMessage)
.create();
alertDialog.show();
} else {
//Do your normal stuff...
}
So this shows a dialog when the app is opened if the app was NOT installed by Google Play. I set the view of the dialog to a TextView because I have a link in the string resource that directs the user to the google play download page. The string resources i threw in there are as such:
Code:
<!-- Illegal download dialog -->
<string name="dialog_title">Illegal Download...</string>
<string name="dialog_message">This app was not downloaded from the Developer\'s desired distributor. Please download the correct application here</string>
Not really illegal, but at least it will get the user's attention
You will of course need to change this to your application's package name "https://play.google.com/store/apps/details?id=<your package name here>"
There are prettier ways of doing this, but this is a quick fix for me. Hope you can get some use of this, and anyone else are free to use this if they desire.
Happy Coding!

thanks
I suppose you can share it on github (that is what I see everyone doing when they have code stuff to share)

ASIC SP said:
thanks
I suppose you can share it on github (that is what I see everyone doing when they have code stuff to share)
Click to expand...
Click to collapse
Yeah but that's usually for entire projects though, this is only a few lines of code
I plan on making a dialog class out of it so it is easier to import to my other projects later on, so I may do it then.
Until I figure out why this happened and if its potentially harmful, I'm adding this to every app I publish. Good luck on your apps!

MattMatt0240 said:
Yeah but that's usually for entire projects though, this is only a few lines of code
I plan on making a dialog class out of it so it is easier to import to my other projects later on, so I may do it then.
Until I figure out why this happened and if its potentially harmful, I'm adding this to every app I publish. Good luck on your apps!
Click to expand...
Click to collapse
Thanks and good luck to you too

Related

Detect Package Launch

I am working on an application and I need to be able to have a service that can detect when applications are opened, and take action based on that.
I have looked everywhere, and have not found a way to do so. I have read documentation on broadcast receivers, intent handlers, I found nothing.
I did however, find an app that can do so. App Protector. It allows password protecting certain applications.
Can anybody please point me in the right direction?
Thanks!
this is actually a very good question. a BroadcastReciever only gets Intents directed at it, and wouldnt see Intents for other classes and Packages.
ill be very interested to know the answer
killersnowman said:
this is actually a very good question. a BroadcastReciever only gets Intents directed at it, and wouldnt see Intents for other classes and Packages.
ill be very interested to know the answer
Click to expand...
Click to collapse
Well I was looking for a BroadcastReceiver that was sent out by the system to indicate that an app was opened, but I did not come across anything.
this isnt possible.. to be able to monitor all intents would make android extremely insecure
http://groups.google.com/group/android-developers/browse_thread/thread/54ddc9d36a24d77b
but there are ways to know when an application is launched. you just have to be creative.
this will give you a list of all the applications running.
Code:
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();
however to know when an app is launched you would need a timed loop and then check between versions of the List to see if there is a new app. this would suck the juice and be inneficient
AppProtector seem to access the eventlog. maybe you could have a ContentObserver attached to the event log
http://developer.android.com/reference/android/util/EventLog.html
http://developer.android.com/reference/android/database/ContentObserver.html
killersnowman said:
this isnt possible.. to be able to monitor all intents would make android extremely insecure
http://groups.google.com/group/android-developers/browse_thread/thread/54ddc9d36a24d77b
but there are ways to know when an application is launched. you just have to be creative.
this will give you a list of all the applications running.
Code:
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();
however to know when an app is launched you would need a timed loop and then check between versions of the List to see if there is a new app. this would suck the juice and be inneficient
AppProtector seem to access the eventlog. maybe you could have a ContentObserver attached to the event log
http://developer.android.com/reference/android/util/EventLog.html
http://developer.android.com/reference/android/database/ContentObserver.html
Click to expand...
Click to collapse
Interesting.
I also found this:
Code:
String str = ((ActivityManager.RunningTaskInfo)this.am.getRunningTasks(1).get(0)).topActivity.getPackageName();
It's one of the things App Protector uses
It starts a new intent, pointing to their application, and passing the parameters of the package you tried to run
Take a look at Tasker it can defiantly do this.
rujelus22 said:
Take a look at Tasker it can defiantly do this.
Click to expand...
Click to collapse
He doesn't want it for scripting, but for use in his own program.
From something awesome

[GUIDE] Implement your own lockscreen-like music controls

Beginner developers, beware! This guide isn't beginner-friendly at all and it's targeted at developers who have some knowledge about Android development.
Or you can use my new library - Remote Metadata Provider, it's MUCH simplier to use.
0. The Introduction
You guys probably seen my apps - Floating Music Widget and Android Control Center.
They both share one feature - good music player integration. They can show you metadata and Floating Music Widget even shows album art. While some players provide API for external music controls(like PowerAmp), the others just somehow integrate with lockscreen. How? Sit down, get a cup of tea, and listen to me.
With the API Level 14 Google introduced class called RemoteControlClient. Citing Google API Reference:
RemoteControlClient enables exposing information meant to be consumed by remote controls capable of displaying metadata, artwork and media transport control buttons.
Click to expand...
Click to collapse
I won't explain how this works - you may go and read some tutorials around the web, there are plenty of them.
Or check API Reference here.
But. Well, we send metadata and album art. Oh, and on 4.3 we can even send playback position. However...how do we receive it? Well, by some reason, I don't know exactly why, Google has hidden this part of API. Maybe they think it's unsere to let you consume other app data, or maybe they just forgot about it. I've asked them multiple times, why did they hid this part of API, but they just ignored me.
So, by posting this article, I hope to maybe somehow make them change their minds and publish this API after all.
1. Getting started
Please note that this guide won't give you Activity examples, or any other things. It will give you the bare bones of the implementation of your own media controls. It's NOT intended to be used by Android/Java newbies.
PLEASE NOTE THAT IT'S A CLOSED API! IT MAY MALFUNCTION OR NOT WORK AT ALL!
Of course, you will need Eclipse IDE.
Also you will need modified Android build platform with hidden and internal API enabled.
There's an excellent guide on how to do this:
Using internal (com.android.internal) and hidden (@hide) APIs
Read it, do all five steps, then come back here for a read.
Please note that you will need to enable hidden APIs for API Level 18(4.3) and one API from 14 to 17. I recommend doing 17.
So, you've enabled hidden and internal API, hacked your ADT plugin, and you're craving for knowledge? Good.
Now some theory.
When the metadata is sent by RemoteControlClient, it is consumed by object called RemoteControlDisplay.
But the problem is, there's no explicit RemoteControlDisplay class, but there is only AIDL interface called IRemoteControlDisplay.
2. Understanding IRemoteControlDisplay
So, let's check which methods this interface has.
void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent, boolean clearing);
This method is used to connect music player to your RemoteControlDisplay.
First parameter is an internal ID of current player.
Second parameter is PendingIntent which will be used for controlling the playback - this is the "address" where you will send commands like "stop playback", "switch to next", etc.
About third parameter...my guess is that it's used when the RemoteControlDisplay is disconnected from current music player. You don't really ned this one.
For next methods I will explain only useful parameters.
void setPlaybackState(int generationId, int state, long stateChangeTimeMs);
This method is called when playback state has changed. For example, it's called when you pause your music.
"state" is obviously the current state of your music player.
It can be one of the following values:
Rarely used:
RemoteControlClient.PLAYSTATE_ERROR - well, there was some kind of error. Normally, you won't get this one.
RemoteControlClient.PLAYSTATE_BUFFERING - the music is buffering and will start playing very-very soon.
Normally used:
RemoteControlClient.PLAYSTATE_PAUSED - the music is paused
RemoteControlClient.PLAYSTATE_PLAYING - the music is playing.
You can check other PLAYSTATE_ constant in RemoteControlClient API reference.
void setTransportControlFlags(int generationId, int transportControlFlags);
In lockscreen it is used for toggling the widget visibility. I couldn't find any appliance for this method in my apps. Well, it sets flags
void setMetadata(int generationId, in Bundle metadata);
Well, that's obvious. It is called when RemoteControlDisplay have to update current track metadata.
The Bundle which we are receiving containing some metadata.
The keys for them are all in class MediaMetadataRetriever.
So, for example, to extract song title, you have to do it this way:
Code:
String title=metadata.getString(Integer.toString(MediaMetadataRetriever.METADATA_KEY_TITLE));
From my research I've found that this Bundle can have the following entries:
Those are for "String" entries:
MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST
MediaMetadataRetriever.METADATA_KEY_ARTIST
MediaMetadataRetriever.METADATA_KEY_ALBUM
MediaMetadataRetriever.METADATA_KEY_TITLE
And this one is "long":
MediaMetadataRetriever.METADATA_KEY_DURATION
void setArtwork(int generationId, in Bitmap artwork);
This one is way too obvious. It gives you the Bitmap with artwork of current song. If there is no artwork, the "artwork" parameter will be null.
void setAllMetadata(int generationId, in Bundle metadata, in Bitmap artwork);
This call just combines previous two.
3. Implementing IRemoteControlDisplay
Hey, I now know everything about RemoteControlDisplay, I will implement my own in split second.
Code:
public class MyRemoteControlDisplay implements IRemoteControlDisplay
Please note that IT WON'T WORK THIS WAY!
As IRemoteControlDisplay is actually a AIDL interface, we need to somehow handle marshalling and unmarshalling of data. But luckily, we don't need to think about it. There is a class which handles basic IPC operations - IRemoteControlDisplay$Stub. We just need to extend it.
So, the right way to implement your own RemoteControlDisplayClass is:
Code:
public class MyRemoteControlDisplay extends IRemoteControlDisplay.Stub
Then you will have to implement methods of IRemoteControlDisplay. However, now listen to me carefully. Please, don't try to write your own super-cool implementation.
Just copy and paste the following code
Code:
public MyRemoteControlDisplay extends IRemoteControlDisplay.Stub {
static final int MSG_SET_ARTWORK = 104;
static final int MSG_SET_GENERATION_ID = 103;
static final int MSG_SET_METADATA = 101;
static final int MSG_SET_TRANSPORT_CONTROLS = 102;
static final int MSG_UPDATE_STATE = 100;
private WeakReference<Handler> mLocalHandler;
MyRemoteControlDisplay(Handler handler) {
mLocalHandler = new WeakReference<Handler>(handler);
}
public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
}
}
public void setArtwork(int generationId, Bitmap bitmap) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget();
}
}
public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
boolean clearing) throws RemoteException {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_GENERATION_ID, clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
}
}
public void setMetadata(int generationId, Bundle metadata) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget();
}
}
public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
}
}
public void setTransportControlFlags(int generationId, int flags) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags).sendToTarget();
}
}
}
Why we have to implement it this way?
Well, it's because those methods calls arrive asynchronously, so, to correctly process them all, we need a Handler. Then we send messages to this Handler with necessary parameters, and it processes them.
But why use this weird WeakReference? Well, I can't explain it better than Google Developers. Citing the source code comment:
/**
* This class is required to have weak linkage
* because the remote process can hold a strong reference to this binder object and
* we can't predict when it will be GC'd in the remote process. Without this code, it
* would allow a heavyweight object to be held on this side of the binder when there's
* no requirement to run a GC on the other side.
*/
Click to expand...
Click to collapse
Tl;dr it's just a clever usage of memory resources.
So, my congratulations! We've implemented hidden IRemoteControlDisplay interface. But now it doesn't actually do anything.
4. Using our RCD implementation
As you can see, the constructor requires a Handler to be passed to it.
But any Handler just won't do, as we have to process messages.
So, you can't just write
Code:
MyRemoteControlDisplay display=new MyRemoteControlDisplay(new Handler());
Then, let's implement our Handler.
Again, I recommend you to use the following code, as it's doing it's job fine. This is the code used by default lockscreen with slight modifications. You can try and implement your own Handler, but this is strongly discouraged, as it can get glitchy. Don't worry, we'll soon get to the part where you can use your imagination
Code:
private int mClientGeneration;
private PendingIntent mClientIntent;
private Bitmap mArtwork;
public static final int MSG_SET_ARTWORK = 104;
public static final int MSG_SET_GENERATION_ID = 103;
public static final int MSG_SET_METADATA = 101;
public static final int MSG_SET_TRANSPORT_CONTROLS = 102;
public static final int MSG_UPDATE_STATE = 100;
Handler myHandler = new Handler(new Handler.Callback() {
[user=439709]@override[/user]
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
//if client generation is correct(our client is still active), we do some stuff to indicate change of playstate
if (mClientGeneration == msg.arg1) updatePlayPauseState(msg.arg2);
break;
//if client generation is correct(our client is still active), we do some stuff to update our metadata
case MSG_SET_METADATA:
if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj);
break;
case MSG_SET_TRANSPORT_CONTROLS:
break;
//if our client has changed, we update the PendingIntent to control it and save new generation id
case MSG_SET_GENERATION_ID:
mClientGeneration = msg.arg1;
mClientIntent = (PendingIntent) msg.obj;
break;
//if client generation is correct(our client is still active), we do some stuff to update our artwork
//while recycling the old one to reduce memory usage
case MSG_SET_ARTWORK:
if (mClientGeneration == msg.arg1) {
if (mArtwork != null) {
mArtwork.recycle();
}
mArtwork = (Bitmap)msg.obj;
setArtwork(mArtwork);
}
break;
}
return true;
}
});
I think you can probably guess what do we do here, but I'll explain anyway.
updatePlayPauseState(msg.arg2) - it's the method where you actually handle the change of playstate.
msg.arg2 is an Integer(or, more correcly, int), which indicates current play state. Please refer to section 2 to see possible play states. For example, you may do check like this:
Code:
updatePlayState(int state) {
if(state==RemoteControlClient.PLAYSTATE_PLAYING) {
setButtonImage(R.drawable.play);
} else {
setButtonImage(R.drawable.pause);
}
}
setArtwork(mArtwork);
It's pretty obvious, do whatever you like with this bitmap, just remember that it can be null.
updateMetadata((Bundle) msg.obj)
That one isn't very easy to handle. There is a bundle containing all of available metadata. So, you can deal with it as you please(you know how to extract data from Bundle, right?), but here's how I do it(modified Google version):
Code:
private void updateMetadata(Bundle data) {
String artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
//if we failed to get artist, then we should try another field
if(artist==null) {
artist=getMdString(data, MediaMetadataRetriever.METADATA_KEY_ARTIST);
}
if(artist==null) {
//if we still failed to get artist, we will return a string containing "Unknown"
artist=mContext.getResources().getString(R.string.unknown);
}
//same idea for title
String title = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE);
if(title==null) {
title=mContext.getResources().getString(R.string.unknown);
}
//album isn't that necessary, so I just ignore it if it's null
String album=getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM);
if((artist!=null)&&(title!=null)) {
setMetadata(artist, title, album);
}
}
private void updatePlayPauseState(int state) {
mPlayButtonState=state;
mService.setPlayButtonState(state);
}
public void setMetadata(String artist, String title, String album) {
mMetadataArtistTextView.setText(artist);
mMetadataTitleTextView.setText(title);
if(album!=null) {
mMetadataAlbumTextView.setText(album);
} else {
mMetadataAlbumTextView.setText("");
}
}
}
private String getMdString(Bundle data, int id) {
return data.getString(Integer.toString(id));
}
You've got the idea.
Okay. So you've implemented your Handler, and created MyRemoteControlDisplayObject. What's next?
5. Registering and unregistering RemoteControlDisplay
In order for your RemoteControlDisplay to be able to receive metadata and album arts, it has to be registered via AudioManager.
You have to get the instance of AudioManager and then call Audiomanager#registerRemoteControlDisplay().
Code:
MyHandler myHandler=new MyHandler();
MyRemoteControlDisplay remoteDisplay=new MyRemoteControlDisplay(myHandler);
AudioManager manager=((AudioManager)mContext.getSystemService("audio"));
mAudioManager.registerRemoteControlDisplay(remoteDisplay);
So, that's it. You've succesfully registered your display. Now it will receive metadata and album art.
However, that's not all.
When the metadata isn't visible to user, you should unregister your RemoteControlDisplay by using this code:
Code:
audioManager.unregisterRemoteControlDisplay(remoteDisplay);
remoteDisplay=null;
mHandler.removeMessages(MSG_SET_GENERATION_ID);
mHandler.removeMessages(MSG_SET_METADATA);
mHandler.removeMessages(MSG_SET_TRANSPORT_CONTROLS);
mHandler.removeMessages(MSG_UPDATE_STATE);
This way you will unregister your RemoteControlDisplay, destroy it(or, actually, just give it garbage collector), and remove all unprocessed messages. This is the correct way to unregister your RemoteControlDisplay.
Please note! You must register your RemoteControlDisplay every time when the View which displays metadata is shown to the user. This is because 4.2.2 and lower versions support only one RemoteControlDisplay, and if system will decide to register it's own RCD, your RCD will be unregistered automatically.
When you're compiling, you have to compile with 4.2.2 modified library for 4.2.2 and lower, and compile with 4.3 modified library for 4.3. That is very important, because if you'll try to launch 4.2.2 implementation on device running 4.3, it will give you AbstractMethodError.
If you have any question regarding the implementation, please ask here. Don't ask "How do I start Eclipse", or anything like that.
And please, if you use this, at least give me a credit. Finding this out was a really hard job.
To understand how it works, I've used source code from Android GitHub repository:
KeyguardTransportControlView.java
Or donate to me, whatever you like more. However, it would be the best if you give me credit and donate to me
Reserved for Android 4.3 implementation.
So, in 4.3 Google change some IRemoteControlDisplay methods.
1. Implementing IRemoteControlDisplay
Those are:
void setTransportControlFlags(int generationId, int transportControlFlags); is replaced by
void setTransportControlInfo(int generationId, int transportControlFlags, int posCapabilities)
The new parameter - posCapabilities - is indicating whether the RemoteControlClient provides information about playback position. It is a bit mask for those (public, but hidden) constants:
0 - no info about playback position
RemoteControlClient.MEDIA_POSITION_WRITABLE - playback position can be changed
RemoteControlClient.MEDIA_POSITION_READABLE - playback position can be read
void setPlaybackState(int generationId, int state, long stateChangeTimeMs); is replaced by
void setPlaybackState(int generationId, int state, long stateChangeTimeMs, long currentPosMs,float speed);
New parameters:
currentPosMs - current playback position in milliseconds.
If it's positive, it's the current playback position.
Negative values means that the position is unknown.
RemoteControlClient.PLAYBACK_POSITION_INVALID means that position is unknown, like if you're listening to live radio.
RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN - that means the music player doesn't provide current position at all, because it's using legacy API(from 4.2.2).
speed - is the playback speed. 1.0 is normal, 0.5 is slower, 2.0 is 2x faster.
The rest stays the same.
However, the IRemoteControlDisplay implementation in my first post doesn't send this kind of data. So, if you want to send this data to your Handler, you may want to pack it into Bundle and send it as Message.obj.
2. Registering RemoteControlDisplay
Now there are two methods:
registerRemoteControlDisplay(IRemoteControlDisplay rcd)
RemoteControlDisplay registered with this method will NOT receive any artwork bitmaps.
Use this method only if you DO NOT NEED ARTWORK.
registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h)
w and h are maximum width and height of expected artwork bitmap. Use this method if you NEED ARTWORK.
3. Multiple RemoteControlDisplays
(FOLLOWING TEXT MAY BE NOT WORKING, AS THIS IS ONLY A THEORY BASED FROM STUDYING OF ANDROID SOURCE CODE)
Until API 18 there could be only one active RemoteControlDisplay. So, that means if you register your RCD, and then system decides to do the same, then your RemoteControlDisplay will be unregistered automatically.
However, this is not the case in 4.3, as from API 18 it does support multiple RemoteControlDisplay. So, in theory, you can just fire AudioManager#registerRemoteControlDisplay. Didn't tried that, however.
And, of course, you have to compile with Android 4.3 library.
Really cool guide. :good:
Thank you.
nikwen said:
Really cool guide. :good:
Thank you.
Click to expand...
Click to collapse
Thanks! I just hope it will have the desired effect and Google will release RemoteControlDisplay API to public, 'cause, you know, now I made it public, there's no reason to hide it now. Now I only need it to be featured on the main page...
How about making it sticky or something?
Dr.Alexander_Breen said:
Thanks! I just hope it will have the desired effect and Google will release RemoteControlDisplay API to public, 'cause, you know, now I made it public, there's no reason to hide it now. Now I only need it to be featured on the main page...
How about making it sticky or something?
Click to expand...
Click to collapse
I voted for it.
The sticky: Contact a mod and if it is relevant to the majority of the users, it will be made sticky.
Those are the mods for the Java development forum: diestarbucks, poyensa, justmpm, mark manning, crachel, Archer
I was looking for this undocumented api's and customized transparent lock screen that can listen for events.
Thank you. I will close my other open thread now.
God is great.
@Dr.Alexander_Breen thanks a lot for this, almost spent the day trying to get this to work with reflection.
Anyway, I still can't get it to work.
I'm trying to do this for my S-View cover mod http://forum.xda-developers.com/showthread.php?t=2368665
But the methods aren't called at all.
I've never used handlers before, so I'm guessing there's a problem with those.
Can you take a look at the source code? Since it's an Xposed module, and you might not know Xposed, I'll state a few things about it
https://github.com/MohammadAG/Xpose...ewpowerampmetadata/SViewPowerampMetadata.java
The mod is not a subclass of Activity, so there's no Context, but I do get the Context used by the S-View widget.
After getting the Context, and the Handler used by the S-View classes, I register the RemoteControlDisplay (method initializeRemoteControlDisplay(Looper))
The rest is mostly your code.
If you're wondering why I construct the Handler in such a weird way, it's because I can't create one on the Xposed module thread (something about Looper.prepare()).
Anyway, any help would be appreciated, if the code seems fine, I guess I'll have to use a service and make the module communicate with that instead, though I can't imagine media buttons being any slower.
@MohammadAG:
Your code looks fine to me, but there is one thing.
You register your RemoteControlDisplay in handleLoadPackage() method. I suppose that this method is called only once, but RemoteControlDisplay needs to be registered every time the metadata view is show to user.
Also, added 4.3 implementation.
Dr.Alexander_Breen said:
@MohammadAG:
Your code looks fine to me, but there is one thing.
You register your RemoteControlDisplay in handleLoadPackage() method. I suppose that this method is called only once, but RemoteControlDisplay needs to be registered every time the metadata view is show to user.
Also, added 4.3 implementation.
Click to expand...
Click to collapse
But that's only if I unregister it right? I'll see about it, maybe I need to do the Handler bit different in Xposed.
Thanks
Sent from my GT-I9500 using xda app-developers app
MohammadAG said:
But that's only if I unregister it right? I'll see about it, maybe I need to do the Handler bit different in Xposed.
Thanks
Sent from my GT-I9500 using xda app-developers app
Click to expand...
Click to collapse
Actually, no. As in 4.2 and lower, there can be only one active RCD. So, in case your system decides to register it's own RCD, it automatically unregisters yours.
Dr.Alexander_Breen said:
Actually, no. As in 4.2 and lower, there can be only one active RCD. So, in case your system decides to register it's own RCD, it automatically unregisters yours.
Click to expand...
Click to collapse
Oh, so that explains why your app displayed Unknown at some point. I guess that was my RCD being registered.
Sent from my GT-I9500 using xda app-developers app
And it's on the portal: Implement Lock Screen-Style Music Controls in Your App
MohammadAG said:
Oh, so that explains why your app displayed Unknown at some point. I guess that was my RCD being registered.
Sent from my GT-I9500 using xda app-developers app
Click to expand...
Click to collapse
So, have you managed to make your app working?
Dr.Alexander_Breen said:
So, have you managed to make your app working?
Click to expand...
Click to collapse
No, actually I haven't :/
I register the display each time the S View screen shows, which is when I want to show metadata, but that doesn't work, the handler's handleMessage method is never called.
MohammadAG said:
No, actually I haven't :/
I register the display each time the S View screen shows, which is when I want to show metadata, but that doesn't work, the handler's handleMessage method is never called.
Click to expand...
Click to collapse
Hmm. I'm afraid this is something with Handler in Xposed. You can, however, move IRemoteControlDisplay implementation to service, which will connect with your Xposed part via AIDL or smth like that.
Also, check, if methods of IRemoteControlDisplay are being called. Like, fire a log message when method is called.
Dr.Alexander_Breen said:
Hmm. I'm afraid this is something with Handler in Xposed. You can, however, move IRemoteControlDisplay implementation to service, which will connect with your Xposed part via AIDL or smth like that.
Also, check, if methods of IRemoteControlDisplay are being called. Like, fire a log message when method is called.
Click to expand...
Click to collapse
I thought about that, but I'm pretty sure it'll use up more memory and introduce a bit of lag (if the service was killed for example).
I was thinking of hooking registerRemoteControlClient and keeping the registered remote(s). Then I can simply get the data from their methods, do you know if they're kept in memory for as long as the app lives?
Sent from my GT-I9500 using xda app-developers app
MohammadAG said:
I thought about that, but I'm pretty sure it'll use up more memory and introduce a bit of lag (if the service was killed for example).
I was thinking of hooking registerRemoteControlClient and keeping the registered remote(s). Then I can simply get the data from their methods, do you know if they're kept in memory for as long as the app lives?
Sent from my GT-I9500 using xda app-developers app
Click to expand...
Click to collapse
Again, please check, if methods of RemoteControlDisplay are being called. Write message to debug log(Log.d) in setMetadata or setAllMetadata methods.
As a workaround, I have this idea.
If I understand correctly, Xposed can hook the method of the class, not the instance. Then you can hook RemoteControlClient methods to get the metadata directly from the clients. Check the API reference to RCC to get necessary methods.
really cool tutorial
Thanks a lot !
Could you post one for implimemtation of IBatteryStats...... etc private battery APIs ??
Sent from my GT-S5302 using Tapatalk 2
sak-venom1997 said:
really cool tutorial
Thanks a lot !
Could you post one for implimemtation of IBatteryStats...... etc private battery APIs ??
Sent from my GT-S5302 using Tapatalk 2
Click to expand...
Click to collapse
Well, I think the answer is "no", because I'm no Google Software Engineer. I'll look into this, however, as it will be simplier, I think.
Something like connecting remote service with IBatteryStats.Stub.asInterface. I'll look into it, however.
Dr.Alexander_Breen said:
Well, I think the answer is "no", because I'm no Google Software Engineer. I'll look into this, however, as it will be simplier, I think.
Something like connecting remote service with IBatteryStats.Stub.asInterface. I'll look into it, however.
Click to expand...
Click to collapse
Connecting to serivice and obtaining data i could manage by diging into source but parsing the info is causing trouble
thanks
Sent from my GT-S5302 using Tapatalk 2

[GUIDE] Using the Share Intent

Hello everyone,
While making an app, I wanted to let the user be able to share some content (shameless plug: from a clearable EditText). So, I looked up how to do this.
In this thread, I will share (pun not even intended) with you how to use the Share Intent yourself, so that your users can also quickly involve anyone they know in what they're doing.
There are some things that I am going to assume you've done:
- You have made your base app
- You have a Button done and set up, only needing a method to execute the Share Intent.
Now, let's get to it!
Step 1 - The method:
First, you have to set up the method. As always, give it a nice and descriptive name, so everyone (including you later, believe me that you'll need it) knows what it does.
Of course, this just follows standard syntax. I'm going to name it share, because simple!
So, you'll get this:
Code:
private void share() {
// This is the method where we share some content
}
Step 2 - The Intent:
You want to make sure that Android recognises your Intent as being a Share Intent. Of course, because of the flexibility of Intents, this is also easily done. Just declare another parameter, which isn't the usual set of Classes.
My Intent will be called shareIntent.
Like so:
Code:
Intent shareIntent = new Intent(android.content.intent.ACTION_SEND);
Step 3 - The type:
When sharing content in Android, you have to let the system know what you're sharing. Naturally, it has to react differently to different types of content. An image can be handled by certain apps, while others can only handle text. Apart from that, the apps have to process the items differently.
This is done by declaring the MIME type, which are unique identifiers for different data types.
Some possible types are text/plain, image/gif and video/mp4.
In this case, we are going to share some text. This is done by adding the following line under the Intent declaration:
Code:
shareIntent.setType("text/plain");
With the setType method, you could target specific apps. However, this is obviously not a good idea. If a user doesn't have that app on their phone, it'll cause trouble. Therefore, just use the right type and let the user select the relevant application.
Step 4 - The Content:
Now for the real work. What are you sharing? Of course, text! But you have to give the Intent that text, because it won't just snuff it out by itself.
How do we do this? Simple, again.
Just create a String and use that. Of course, you can hard code a String in the Intent, but it's best to use a variable. After all, you're probably going to be sharing dynamic content.
This is done as follows, though you should really know this by now:
Code:
String sharedString = "Hey, we are sharing!";
Step 5 - The extras:
You have to also give the Intent its extra information. For this example, we'll be setting two types of extras: a subject and the body.
This way, there is flexibility. If the user chooses to share the text using an email application, the subject will also be used. If they don't, it won't be used.
This is done by adding the following lines to your sharing method:
Code:
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "This is the subject");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, sharedString);
Step 5 - The Chooser:
Whenever you share something, you see the Dialog pop up for you to select the app you want to use in your sharing the content. This is the next and last step in this guide, and is basically just starting the Intent with a special parameter.
Not every type of media can be shared to every app. When you share certain content, Android looks at what apps have declared themselves candidates for that MIME type.
So, if you are not seeing certain apps appear, check whether the app can work with that MIME type!
Start the Intent like this:
Code:
startActivity(Intent.createChooser(shareIntent, "Share via"));
Of course, the title to the chooser doesn't have to be "Share via". It can be any other text or variable (keep this in mind for apps that have translations!).
Facebook doesn't do this right! The facebook app doesn't do sharing right, so it will probably not show up in the list of apps that you might see when following the tutorial. To counteract this, target the app using the specific API.
Have fun sharing, and thanks for reading!
P.S.: Images can be added, should anyone want me to do so.
I also found this for the ActionBar very interesting: http://developer.android.com/reference/android/support/v7/widget/ShareActionProvider.html
nikwen said:
I also found this for the ActionBar very interesting: http://developer.android.com/reference/android/support/v7/widget/ShareActionProvider.html
Click to expand...
Click to collapse
True, the ShareActionProvider is quite nice but has one really big downside: You have to update it with the Intent BEFORE the user clicks the item, and there is no workaround. So if you want to generate an image when the user clicks share, you cannot use the ShareActionProvider.
And thanks for the guide OP!
SimplicityApks said:
True, the ShareActionProvider is quite nice but has one really big downside: You have to update it with the Intent BEFORE the user clicks the item, and there is no workaround. So if you want to generate an image when the user clicks share, you cannot use the ShareActionProvider.
And thanks for the guide OP!
Click to expand...
Click to collapse
Wouldn't it be possible to extend the class? Maybe it could be achieved that way.
nikwen said:
Wouldn't it be possible to extend the class? Maybe it could be achieved that way.
Click to expand...
Click to collapse
Could work, but I have no idea what methods to override... I need to have a closer look at this.

[Q] Hack for rooted S5 to keep GPS on regardless of toggle?

Is there such a mod? Need to locate some of my business phones regardless of what the user sets the location setting to.
hockeyfreak said:
Is there such a mod? Need to locate some of my business phones regardless of what the user sets the location setting to.
Click to expand...
Click to collapse
I can't believe that you tried searching for an answer before posting as this has been asked and answered more than once in the forums before.
GPS is a heavy draw on battery and this is an niche request. Given that it is for business use, perhaps you should consider paying someone to make you a custom app.
Alternately, go look in the Play store to see if there is an existing app that does what you want.
Or you could use the xposed framework or tasker to hook onto the method that sets the GPS in the settings.
Or set a BroadcastReceiver service to listen for any change to the GPS status and renable it if changes. e.g.
Code:
String provider = Settings.Secure.getString(getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (!provider.contains("gps")) {
// if gps is disabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings","com.andr oid.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
/*
* Toast.makeText(getApplicationContext(), "GPS On Success",
* Toast.LENGTH_SHORT).show();
*/
Code untested by me
Credit to ken.okech.94
.

Intent filters

Ok so i used to be a very experienced actionscript user. But i recently wanted to get back into programming so im learning java now or rather trying to.
So im trying to understand the xml side of this so far and have some questions im hoping u guys can answer.
activities
So as i understand it an activity is a screen in an app. So for example the standard launcher on my phone has pages of apps on my main screens. Each one of those would be an activity? And then another activity for when i press the button to display all installed apps?
Have i understood that properly?
intent filters
This is where im getting confused. Ive googled it and read as much as i can find. As i read it, feel like someones explaining rocket science to a 5 year old.
The words component and instances is being thrown around enough that i got no clue whats even being said. What i have understood is it gives data to the activity.
So a best guess from my partwould be its telling it how the screens going to work or maybe like if theres going to be a button on it maybe. Or perhaps it means something different like just the properties sort of stuff like screen size or stuff of that nature.
As u guys can probably tell im confused beyond comprehension. I got no idea how good my grasp is of any of this. But if theres someone out there kind enough to dumb it down a bit so normal people can understand it. Id be very gratefull.
Bump
Bump
Hey,
unfortunately i cant answer your question. This is a part of android I don't understand too.
I think you should post your question again in the Question and Answer forum of XDA. http://forum.xda-developers.com/android/help maybe there is an developer who can help you.
Greetings
Thanks ill post there and see if it makes any difference
Android apps run in sandboxes. Consider a huge box partitioned into 'n' number of sections. Each partitions represent a place in android environment where app can reside. By sandboxing, app are given unique ID(UID) when they start a process. Only apps having same (UID) can access the app's resources so no malicious app can peek into the resources of other app.
If apps cannot see other resources, how could they communicate within apps? Thats where intent comes in. Intents are like post letters and android is the postman. You can either give:
1. Recipient address, here, the package name of the app for which the intent is to be sent and may include your data in the intent if there is any and the postman (android) delivers it to the right person (target app). This is also known as explicit intent because you know the target class to call
2. Intent filter - This is not as specific as the first one. Here, your app has to perform something using an external app but your app doesnt know of the other apps which could perform the action. So, this time it will go for a broadcast and say "Hey! I need to take a picture! All camera apps please come in" and the broadcast is sent by android which displays list of apps which respond to this broadcast. When the user chooses the app to perform the action, the app fires, performs the task for your app, return the data to your app in form of intent result.
To register an app to respond to this type of intent, the app specifies something called intent-filter in their manifest which says the android, in our example context "I can perform camera action". So next time intent for camera action is sent, the app is in the list of apps to perform action with. This type of intent in implicit intent as you let the android and user decide the app. You can also specify your own custom intent-filters apart from standard android ones.
vijai2011 said:
Android apps run in sandboxes. Consider a huge box partitioned into 'n' number of sections. Each partitions represent a place in android environment where app can reside. By sandboxing, app are given unique ID(UID) when they start a process. Only apps having same (UID) can access the app's resources so no malicious app can peek into the resources of other app.
If apps cannot see other resources, how could they communicate within apps? Thats where intent comes in. Intents are like post letters and android is the postman. You can either give:
1. Recipient address, here, the package name of the app for which the intent is to be sent and may include your data in the intent if there is any and the postman (android) delivers it to the right person (target app). This is also known as explicit intent because you know the target class to call
2. Intent filter - This is not as specific as the first one. Here, your app has to perform something using an external app but your app doesnt know of the other apps which could perform the action. So, this time it will go for a broadcast and say "Hey! I need to take a picture! All camera apps please come in" and the broadcast is sent by android which displays list of apps which respond to this broadcast. When the user chooses the app to perform the action, the app fires, performs the task for your app, return the data to your app in form of intent result.
To register an app to respond to this type of intent, the app specifies something called intent-filter in their manifest which says the android, in our example context "I can perform camera action". So next time intent for camera action is sent, the app is in the list of apps to perform action with. This type of intent in implicit intent as you let the android and user decide the app. You can also specify your own custom intent-filters apart from standard android ones.
Click to expand...
Click to collapse
Gave u a thanks fkr that very useful responce. Thank you. So if ive understood this right. If i want to take a picture for example the intent filter part basically calls out for an external app to perform the action. With intent filter so basically when an app asks u with that menu what app youd like to choose thats an intent filter? And implicent thats the same menu or android just chooses it for you? Im trying to picture it from the user-side
Recipient address seems straight forward. You know u need an app and what its called. So u dont even need the user to select anything.
scorpafied said:
Gave u a thanks fkr that very useful responce. Thank you. So if ive understood this right. If i want to take a picture for example the intent filter part basically calls out for an external app to perform the action. With intent filter so basically when an app asks u with that menu what app youd like to choose thats an intent filter? And implicent thats the same menu or android just chooses it for you? Im trying to picture it from the user-side
Recipient address seems straight forward. You know u need an app and what its called. So u dont even need the user to select anything.
Click to expand...
Click to collapse
Your understanding on implicit intent is correct. To make it even more short an precise,
An intent is an abstract definition of the operation to be performed by the app
Click to expand...
Click to collapse
When the target action is known, say you invoke a second activity of you app. You know the target action (the class name), that is your implicit intent. You decide what action to perform without user intervention here. Explicit usually needs user input for inter-app communication to take place.
Examples of few implicit intents:
Starting an activity
Starting a service
vijai2011 said:
Your understanding on implicit intent is correct. To make it even more short an precise,
When the target action is known, say you invoke a second activity of you app. You know the target action (the class name), that is your implicit intent. You decide what action to perform without user intervention here. Explicit usually needs user input for inter-app communication to take place.
Examples of few implicit intents:
Starting an activity
Starting a service
Click to expand...
Click to collapse
Ok cool. So recipient is when we choose the app. Intent is whwn they get a menu to choose it. And implicent is is when android chooses it for them.
Sounds simple enough. Thanks for all the help buddy
And would i be right in assuming that the actions we put in intent filters and the others in form it of stuff like when its triggered, how often and so forth?

Categories

Resources