How do I bind my service to two clients? - android

I have a background service running and I would like to use AIDL to be able to communicate with 3rd party apps .
I experimented with an app communication using AIDL and it's working great .
my question is what if I want to communicate with another app,
how do I filter which app is binding at the moment?
I have tried filtering with:
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.d("INTENT",intent.getDataString())
return (new IpPortBinder(getApplicationContext()));
}
but it crashes, because intent.getDataString() is null for some reason. so which method should I use here?

You can filter the intents in the androidmanifest file of your service project.
steps as below:
1) define the filter in service's manifest file.
<service android:name="com.x.y.servicename">
<intent-filter >
<action android:name="getdata" />
</intent-filter>
</service>
2)
while calling binding the service call the bindservice from the client app with this intent
Intent i=new Intent();
i.setAction("getdata");
ret=actContext.bindService(i, AddServiceConnection, Service.BIND_AUTO_CREATE);
the step 2 can be called from instance definition of ServiceConnection in the activity code.

Related

Android Intent reopening activity

I have an issue that I have not found a solution to on this site, but if this is a duplicate question, I apologize.
I am developing an application that serves as a terminal for registering when employees start/finish work, among numerous other things. The way it works is that with NFC switched-on, they scan their NFC cards and my app reads them and ultimately sends the appropriate information to the server.
However, if the app is already open (it's supposed to be open all the time, so this is an issue) and an NFC card is scanned, it reopens the app. Of course, this is done because I have set it that way in the manifest. But I can not find a way to have my app recieve the NFC scan intent if I do not add all of these lines in the manifest:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
I have tried just writing without the but in that case it does not read the card, but instead the program chooser comes up on the phone, or if the phone does not have an appropriate app it simply says "NFC read error".
Does anyone have a solution for this? This is the last step in my project, and I have had a lot of trouble with it, and would appreciate any help. It's probably something simple that I'm just not seeing, but I'd appreciate it either way.
Android activities have different launch modes. If you set single instance it will use already opened activity and doesn't create a new activity. You can read the new intent in override method onNewIntent()
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// read intent values here
}
For various activity elements
You can use broadcastReceiver,
- first initiate the receiver to your activity
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("whateveryouwant");
notificationBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// here you can read the intent and customize the action;
int usage = intent.getIntExtra("usage",1000);
}
}
};
second register the broadcast
registerReceiver(notificationBroadcastReceiver,intentFilter);
At end unregister to the broadcast in the onDestroy method
#Override
protected void onDestroy() {
if(notificationBroadcastReceiver != null){
unregisterReceiver(notificationBroadcastReceiver);
notificationBroadcastReceiver = null;
}
super.onDestroy();
}
after doing that instead of intenting activity you can sendBroadcast()
a little guide: https://developer.android.com/reference/android/content/BroadcastReceiver.html
hope it will be helpfull

Android IPC, Service Not Getting Instantiated

I have a Service which resides inside a lib project like this
public abstract class MyService extends Service{
//service body here
}
I have my aidl file set up to communicate with the remote service which also included in the lib project copying the aidl file here
package mypackage;
// Declare the communication interface which holds all of our exposed functions.
interface IMyService {
//interface body here
}
Inside the lib manifest I have declared the service like this
<service
android:name="mypackage.core.MyService"
android:enabled="true"
android:exported="true"
android:process=":remote" >
<intent-filter>
<action android:name="mypackage.IMyService" />
</intent-filter>
</service>
I have included this lib in my app but when I try to bind the service from the app it is not getting instantiated. Can any one suggest me what I am doing wrong and if so guid me a way out. The service in is starting inside another class which belongs to the lib like this
try{
Intent i = new Intent(MyService.class.getName());
i.setPackage("mypackage");
// start the service explicitly.
// otherwise it will only run while the IPC connection is up.
mAppContext.startService(i);
boolean ret = mAppContext.bindService(i,
mConnection, Service.BIND_AUTO_CREATE);
if(!ret){
MyLogger.log("Error");
}
}catch(Exception e){
MyLogger.log("err");
}
The service bound API always returns false what would be the issue. Is this the prominent way of creating a RemoteService ? Do I need to add this service in the app manifest if so how ?
what would be the issue
First, your Intent does not match your <service>.
Intent i = new Intent(MyService.class.getName());
You are passing in an action String that looks something like mypackage.core.MyService. However, that is not the <action> for your Service:
<action android:name="mypackage.IMyService" />
Hence, your Intent is not matching anything, and you cannot bind.
Second, your Service is very insecure. Any app that wants to can bind to it. If you want other apps to bind to it, that's fine, but please secure it with some permission, so the user gets a vote for what apps can bind to it.
Third, you are binding using an implicit Intent, one that uses stuff like an action string. That won't work on Android 5.0+, as you can no longer bind to a service using an implicit Intent. Using an implicit Intent to discover a service is fine, but you then need to convert the Intent to an explicit one, that incorporates the component name. Here is how I do this in this sample app:
#Override
public void onAttach(Activity host) {
super.onAttach(host);
appContext=(Application)host.getApplicationContext();
Intent implicit=new Intent(IDownload.class.getName());
List<ResolveInfo> matches=host.getPackageManager()
.queryIntentServices(implicit, 0);
if (matches.size()==0) {
Toast.makeText(host, "Cannot find a matching service!",
Toast.LENGTH_LONG).show();
}
else if (matches.size()>1) {
Toast.makeText(host, "Found multiple matching services!",
Toast.LENGTH_LONG).show();
}
else {
Intent explicit=new Intent(implicit);
ServiceInfo svcInfo=matches.get(0).serviceInfo;
ComponentName cn=new ComponentName(svcInfo.applicationInfo.packageName,
svcInfo.name);
explicit.setComponent(cn);
appContext.bindService(explicit, this, Context.BIND_AUTO_CREATE);
}
}
Is this the prominent way of creating a RemoteService ?
Few people create remote services. They are difficult to secure, difficult to deal with version changes in protocol, etc. And, in your case, I do not know why you think you need a remote service, since you are clearly binding to the service from your own app.

"Private" intent filter for self app use only

I have created a file explorer and register
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
But I don't want my internal file explorer is begin shown for user to choose when another app send implicit intent with "Openable" category. How can I do so? Should I just create my own action name?
I don't have the explicit one because I want user to choose other file explorer within my app.
If it's important that only your own app is able to start one of your components, set the exported attribute to "false" for that component in the manifest.
if you asking me - I think that for your situation the best thing is to create your own intent filter (as you sugested in your question), because if you declare your activity to receive a system built in broadcast - it have a meaning. so what's the point using this built in broadcast, if you kind of "breaking his contract" from a system point of view, and want to ignore it in some cases?
if you'll decide to use this built in filter anyway although what I've suggested, the way to achieve what you want is:
register your receiver not in the manifest, but in the onCreate() method of your first launch activity, and unregister him in the onDestroy().
that way your activity won't be registered when none of your activities are foreground - that is close to state which application is close from users point of view.
in case you are not sure how it's done, that's the way:
private BroadcastReceiver mMyCustomReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mMyCustomReceiver, IntentFilter.create(YOUR_FILTER_ACTION_COMMAND, YOUR_FILTER_DATA_TYPE));
}
#Override
protected void onDestroy() {
unregisterReceiver(mMyCustomReceiver);
super.onDestroy();
}
I agree with Chris Stratton and Tal Kanel.But instead you can use specific "Data" in your intent filter.Documentation says:
An Intent object that contains neither a URI nor a data type passes
the test only if the filter likewise does not specify any URIs or data
types.
So if an intent has "Openable" category and has not data part that matches your intent filter specific data part,your internal file explorer will be not shown for user.
You could use an 'activity-alias' to make a 'copy' of the activity with android:exported="false" and the private intents?
If you are willing to invoke your activity via an explicit intent (ie, giving the target component name) then you can omit having an intent filter for that activity.

Android: Why intent doesn't received by broadcastreceiver?

I have a few intents that activity sends to service.
All of those are registered in manifest:
<service android:name=".location.LocationService" android:label="#string/location_service_started">
<intent-filter>
<action android:name="#string/location_service_set" />
<action android:name="#string/location_service_start" />
<action android:name="#string/location_service_stop" />
</intent-filter>
</service>
But only location_service_start and location_service_stop intents are received. What could be the reason?
There is my receiver code:
private BroadcastReceiver LocationServiceReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(getString(R.string.location_service_stop)))
{
showMessage("stop");
}
if(intent.getAction().equals(getString(R.string.location_service_start)))
{
showMessage("start");
}
if(intent.getAction().equals(getString(R.string.location_service_set)))
{
showAlertBox("set");
}
}
};
So I never see "set" message. I've even tried put sendBroadcast for "start" and "set" messages in the same place, but everything still the same. "start" - OK, "set" - never received.
Functions that fires intents:
protected void start()
{
Intent intent = new Intent(getString(R.string.location_service_start));
getApplicationContext().sendBroadcast(intent);
}
protected void set(double lat, double lon, double rad)
{
Intent intent = new Intent(getString(R.string.location_service_set));
intent.putExtra("lat", lat);
intent.putExtra("lon", lon);
intent.putExtra("rad", rad);
getApplicationContext().sendBroadcast(intent);
}
Both are correct send, without errors, actions are correct.
UPD:
Oh, my fault. I forgot to add filter.addAction... for new intent.
I'm sorry. But answers was really useful! Thank you!
All of those are registered in manifest:
Generally, you do not use string resources for action strings in an <intent-filter>, because you never want to internationalize them.
Generally, you do not use an <intent-filter> at all with a service unless you are exposing that service to third-party apps. In fact, right now, you are exposing your service to third-party apps, so anyone can send these commands to your service.
But only location_service_start and location_service_stop intents are received
No, none of them are received by the service. You are sending broadcasts in the Java code. Services do not receive broadcasts.
Functions that fires intents:
Do not use getApplicationContext() unless you know what you are doing. Whatever you are calling getApplicationContext() on is a Context, so you can just call sendBroadcast() on it.
Copy & Paste from this question I just answered. Should be the same issue.
You have to put each <action /> tag inside a seperate <intent-filter /> tag in your manifest.
This should be a bug, since the doc states you can put more than one action inside a filter tag:
Zero or more action [..] tags should be included
inside to describe the contents of the filter.
Source

Overriding the hardware buttons on Android

Is it possible to override the function of a hardware button programmically on a droid? Specifically, I'd like to be able to override the camera button on my phone programmically. Is this possible?
How to Handle Camera Button Events
As soon as camera button is pressed a broadcast message is sent to all the applications listening to it. You need to make use of Broadcast receivers and abortBroadcast() function.
1) Create a class that extends BroadcastReceiver and implement onReceive method.
The code inside onReceive method will run whenever a broadcast message is received. In this case I have written a program to start an activity called myApp.
Whenever hardware camera button is clicked the default camera application is launched by the system. This may create a conflict and block your activity. E.g If you are creating your own camera application it may fail to launch because default camera application will be using all the resources. Moreover there might be other applications which are listening to the same broadcast. To prevent this call the function "abortBroadcast()", this will tell other programs that you are responding to this broadcast.
public class HDC extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// Prevent other apps from launching
abortBroadcast();
// Your Program
Intent startActivity = new Intent();
startActivity.setClass(context, myApp.class);
startActivity.setAction(myApp.class.getName());
startActivity.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(startActivity);
}
}
}
2) Add below lines to your android manifest file.
<receiver android:name=".HDC" >
<intent-filter android:priority="10000">
<action android:name="android.intent.action.CAMERA_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
The above lines are added to your manifest file to tell the system that your program is ready to receive broadcast messages.
This line is added to receive an intimation when hardware button is clicked.
<action android:name="android.intent.action.CAMERA_BUTTON" />
HDC is the class created in step 1(do not forget the ".")
<receiver android:name=".HDC" >
The "abortBroadcast()" function is called to prevent other applications from responding to the broadcast. What if your application is the last one to receive the message? To prevent this some priority has to be set to make sure that your app receives it prior to any other program. To set priority add this line. Current priority is 10000 which is very high, you can change it according to your requirements.
<intent-filter android:priority="10000">

Categories

Resources