I would like to provide a service that can be called by other app. Therefore, I have a service and an aidl. But when I try to have a separate application to bind this service (bindService), it just returns me false which means fail. Here is my code.
PS: context is already the ApplicationContext which obtained by calling getApplicationContext()
Code that try to bind the service
private static ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
sService = XXXService.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName name) {
sService = null;
}
};
private static synchronized XXXService getService(final Context context) {
if (sService != null) {
return sService;
} else {
intent.setClassName(context.getPackageName(), "com.xxx.someservice");
if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
Log.i(TAG, "can bind");
} else {
Log.i(TAG, "can not bind");
}
return sService;
}
}
AndroidManifest
<service android:name="com.xxx.someservice"
android:process=":main"
android:exported="true"/>
This seems basically right. I think the issue is that intent.setClassName(context.getPackageName(), "com.xxx.someservice"); should be intent.setClassName("Your.package.name.with.the.service", "com.xxx.someservice"); . context.getPackageName() returns the current package name, so this would work if you were trying to bind in your own package, but your question makes it seem like you are doing it in a separate package.
Using an action name for service worked for me.
E.g:
<service
android:name="..."
android:process="..." >
<intent-filter>
<action android:name="your-unique-action-name" />
</intent-filter>
</service>
And:
...
bindService(new Intent("your-unique-action-name"), mServiceConnection, BIND_AUTO_CREATE);
Related
I referred to all the other StackOverflow posts about this problem and I can't get it to work properly.
My goal is to write an app with no main activity, just a service. You should be able to bind to it from a seperate app and interact with it using AIDL.
I previously had both the service and the activity calling it in the same app and it worked flawlessly. But I need to get it working between two seperate apps.
The onBind() of the service looks like this:
#Nullable
#Override
public IBinder onBind(Intent intent) {
// This binds the bluetooth service itself to the logger service, do this when the logger service itself is bound
Intent serviceIntent = new Intent(this, BluetoothService.class);
intent.setPackage(this.getPackageName());
Log.d(getClass().getName(), "started");
if(bluetoothService == null) {
if (this.bindService(serviceIntent, bluetoothServiceConnection, BIND_AUTO_CREATE)) {
Log.d(getClass().getName(), "returned the service");
return mBinder;
} else {
Log.d(getClass().getName(), "returned null");
return null;
}
} else {
Log.d(getClass().getName(), "returned the service");
return mBinder;
}
}
The service itself binds to another service, but all of the bluetooth stuff works already.
The Manifest of the app with the service looks like this:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<application
android:label="#string/app_name">
<service
android:label="LoggerService"
android:name="io.modum.ble.LoggerService"
android:exported="true">
<intent-filter>
<action android:name="io.modum.ble.LoggerService" />
</intent-filter>
</service>
<service android:name="io.modum.ble.service.BluetoothService" />
</application>
In my activity, I bind to it like this:
Intent intent = new Intent();
ComponentName componentName = new ComponentName("io.modum.modum_ble_service", "io.modum.ble.LoggerService");
intent.setComponent(componentName);
boolean success = getApplicationContext().bindService(intent, new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(getClass().getName(), "Service connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
Log.d(getClass().getName(), String.valueOf(success));
The AIDL files have the exact same package name in both applications.
No exception is called, everything works except onServiceConnected is not called.
bindService() returns true, the service receives the intent and is correctly started, "returned the service" is logged, but onServiceConnected() is never called.
I got it running, what was missing was
intent.setPackage("io.modum.modum_ble_service)
Note that the package name is the name of the app, not the package the service is in. Use the package name displayed in LogCat.
My issue here is more the result of the framework I'm using than Android itself. My app needs to register a ContentObserver after the user has installed a specific plugin associated with the AWARE framework. The framework has a sensor for installation of plugins, and sends a broadcast once this happens. Documentation can be found here: http://www.awareframework.com/installations/
I would like to accomplish this using a BroadcastReceiver.
I have a few questions regarding how to properly do this:
The way I interpret this documentation and Android is that if I register a BroadcastReceiver in my Manifest file with the intent filter "Installations.EXTRA_PACKAGE_NAME", every time a package is installed, it will activate my InstallationReceiver. If my understanding is still correct, I will be able to use getAction() on the received intent to parse the package name. Does this look like a correct understanding? Do intents works this way?
Is it proper to have my BrodcastReceiver in my Service class? Or should I make it a standalone class?
Did I register my receiver properly?
My MainService code:
package hcii.tracker;
public class MainService extends Service {
public static final Uri ACTIVITY_URI = Uri.parse("content://com.aware.plugin.google.activity_recognition.provider/plugin_google_activity_recognition");
public HashMap<Uri,ContentObserver> mContentObservers;
public void onCreate(){
Log.d("SERVICE", "Service created!");
Context context = this;
mContentObservers = new HashMap<Uri,ContentObserver>();
//Activate installations sensor
Aware.setSetting(context, Aware_Preferences.STATUS_INSTALLATIONS, true);
//Activate Accelerometer
Aware.setSetting(this, Aware_Preferences.STATUS_ACCELEROMETER, true);
//Set sampling frequency
Aware.setSetting(this, Aware_Preferences.FREQUENCY_ACCELEROMETER, 60);
Aware.setSetting(getApplicationContext(), "frequency_google_fused_location", 60,
"com.aware.plugin.google.fused_location");
Aware.startPlugin(getApplicationContext(), "com.aware.plugin.google.fused_location");
Aware.startPlugin(getApplicationContext(), "com.aware.plugin.google.activity_recognition");
sendBroadcast(new Intent(Aware.ACTION_AWARE_REFRESH));
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
try {
ContentObserver observer = mContentObservers.get(ACTIVITY_URI);
getContentResolver().unregisterContentObserver(observer);
mContentObservers.remove(ACTIVITY_URI);
} catch (IllegalStateException ise) {
Log.d("SERVICE", "No ContentObservers registered");
}
}
public class ActivityRecognitionObserver extends ContentObserver {
public Uri CONTENT_URI = Uri.parse("content://com.aware.plugin.google.activity_recognition.provider/plugin_google_activity_recognition");
public ActivityRecognitionObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// Get the latest recorded value
Log.d("OBSERVER", "Change in activity data detected");
Cursor activity = getContentResolver().query(CONTENT_URI, null, null, null,
"activity_name" + "DESC LIMIT 1");
if( activity != null && activity.moveToFirst() ) {
// Here we read the value
String activity_name = activity.getString(activity.getColumnIndex("activity_name"));
if (activity_name.equals("in_vehicle")){
Aware.setSetting(getApplicationContext(), "frequency_google_fused_location", 60,
"com.aware.plugin.google.activity_recognition");
Log.d("OBSERVER", "Recognized in vehicle");
Aware.startPlugin(getApplicationContext(), "com.aware.plugin.google.activity_recognition");
}
else {
Aware.setSetting(getApplicationContext(), "frequency_google_fused_location", 180,
"com.aware.plugin.google.activity_recognition");
Log.d("OBSERVER", "Recognized on foot");
Aware.startPlugin(getApplicationContext(), "com.aware.plugin.google.activity_recognition");
}
}
if( activity != null && ! activity.isClosed() ) activity.close();
}
}
public class InstallationReceiver extends BroadcastReceiver {
public InstallationReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.equals("com.aware.plugin.google.activity_recognition")){
ActivityRecognitionObserver so = new ActivityRecognitionObserver(new Handler());
getContentResolver().registerContentObserver(ACTIVITY_URI, true, so);
mContentObservers.put(ACTIVITY_URI, so);
Log.d("SERVICE", "Observer registered");
}
}
}
}
Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="hcii.tracker" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
tools:replace="android:icon, android:theme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MainService"
android:exported="false" />
<receiver android:name="hcii.tracker.MainService$InstallationReceiver" >
<intent-filter>
<action android:name="Installations.EXTRA_PACKAGE_NAME" >
</action>
</intent-filter>
</receiver>
...
There are several problems here:
1) You can use an inner class for your BroadcastReceiver, but if so it must be declared static, because Android needs to be able to instantiate the class itself using new. This is not possible in your current architecture (because the class is an inner class). In general it is better (easier) to use a stand-alone class for this.
2) Your Intent filter is wrong. The linked documentation from Aware indicates that the broadcast Intent is Installations.ACTION_AWARE_APPLICATION_ADDED, so your intent filter needs to look like this:
<intent-filter>
<action android:name="Installations.ACTION_AWARE_APPLICATION_ADDED"/>
</intent-filter>
3) Once you have declared the BroadcastReceiver correctly, it will be triggered whenever Aware adds a plugin. The package name of the installed plugin is put into an "extra" in the Intent. To determine which plugin has been installed, you need to do something like this:
public void onReceive(Context context, Intent intent) {
String packageName = intent.getStringExtra("Installations.EXTRA_PACKAGE_NAME");
if (packageName != null && packageName.equals("your.plugin.package.name") {
// Do your stuff here...
}
}
I have been searching for a sample or tutorial to change the Interruptions in Lollipop. But I didn't find any complete one. I saw ideas or hints but not a complete one. With those ideas I have created a NotificationListener which is executed but I get this error:
java.lang.ClassCastException:
android.service.notification.NotificationListenerService$INotificationListenerWrapper cannot be cast to My.App.MyNotificationListenerService
My Manifest:
<service android:name=".MyNotificationListenerService"
android:label="Some text here"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
My MyNotificationListenerService class:
public class MyNotificationListenerService extends NotificationListenerService
{
#Override public void onCreate()
{ super.onCreate();
}
#Override public void onDestroy()
{ super.onDestroy();
}
#Override public IBinder onBind(Intent intent)
{ return super.onBind(intent);
}
}
My activity:
Intent serviceIntent = new Intent(MyActivity.this, MyNotificationListenerService.class);
MyServiceConnection oMyServiceConnection = new MyServiceConnection();
bindService(serviceIntent, oMyServiceConnection, Context.BIND_AUTO_CREATE);
//Now we wait onconnect
class MyServiceConnection implements ServiceConnection
{ #Override public void onServiceConnected(ComponentName name, IBinder binder)
{ MyNotificationListenerService oMyNotificationListenerService= ((MyNotificationListenerService ) binder).getService(); <-- here is where I get the ClassCastException
int iFilter = NotificationListenerService.INTERRUPTION_FILTER_PRIORITY; //Or INTERRUPTION_FILTER_ALL or INTERRUPTION_FILTER_NONE
oMyNotificationListenerService.requestInterruptionFilter(iFilter);
}
#Override public void onServiceDisconnected(ComponentName name)
{
}
}
As seen in the source of NotificationListenerService, NotificationListenerService already implements onBind() and is how the NotificationListenerService communicates with the system.
By overriding onBind() to return your own interface, none of the methods that communicate with the system will work - you should see verbose level log messages along the lines of "Unable to contact notification manager".
You can use other methods for communicating with your service such as LocalBroadcastManager.
I want to open my application immediately when S Pen is detached , How can you do this, if the methods put under onSPenDetached is only called when my application is opened again?
Thanks,
Chandu
The following works on my Galaxy Tab A 9.7 with S-Pen (SM-P550) running Android 5.0.2.
Attaching and detaching the stylus creates Broadcast Intents of type com.samsung.pen.INSERT with a booleanExtra named penInsert of false if detached and true if put back into the device.
Thus a Broadcast Receiver can be created that filters this kind of events. The following code is for such a Broadcast Receiver which starts OneNote if the stylus is detached:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class SPenDetachIntentBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent penInsertIntent) {
if (!penInsertIntent.getBooleanExtra("penInsert", true)) {
try {
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage("com.microsoft.office.onenote");
context.startActivity(launchIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
In the Manifest file you need to declare it as a receiver listening for com.samsung.pen.INSERT Broadcast Intents with an intent filter. The following entry in a project's AndroidManifest.xml declares SPenDetachBroadcastReceiver, generates an instance and makes it listening for com.samsung.pen.Insert Broadcast Intents:
<receiver
android:name=".SPenDetachIntentBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.samsung.pen.INSERT" />
</intent-filter>
</receiver>
The advantage over using registerSPenDetachmentListener on an SPenEventLibrary object to register a Service with an onSPenDetached method implemented is that you do not need any additional library files and you also do not need additional permissions.
You will need to create a BroadcastReceiver and a Service.
The service:
public class SPenService extends Service {
SPenEventLibrary mSPenEventLibrary = new SPenEventLibrary();
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mSPenEventLibrary.registerSPenDetachmentListener(this, new SPenDetachmentListener() {
#Override
public void onSPenDetached(boolean bDetached) {
if (bDetached) {
Toast.makeText(SPenService.this, "S Pen Detached", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(SPenService.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
Toast.makeText(SPenService.this, "S Pen Inserted", Toast.LENGTH_SHORT).show();
}
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
mSPenEventLibrary.unregisterSPenDetachmentListener(this);
}
}
The receiver:
public class SPenReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
context.startService(new Intent(context, SPenService.class));
}
}
}
The manifest (inside the <application> tag):
<receiver android:name=".SPenReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".SPenService" >
</service>
I have service which include connecting to bluetooth device.I'm calling this service from my first activity. And service successfully created and started . But when i use bind in first activity to call method in service, its not executing. I referred to LocalService example
My service code:
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
public class LocalBinder extends Binder {
public BluetoothServices getService() {
// Return this instance of LocalService so clients can call public methods
return BluetoothServices.this;
}
}
public void SendData(){
Log.d("msg", "Send msg");
}
I'm using below code in my first activity:
BluetoothServices mService;
boolean mBound = false;
#Override
public void onStart(){
super.onStart();
Intent btservices = new Intent(getApplication(),BluetoothServices.class);
startService(btservices);
bindService(btservices, mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(mBound){
mService.SendData();
}
}
What is the problem in above code?Why it is not binding and calling method?
My manifest:
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:debuggable="true"
android:icon="#drawable/logo_50"
android:theme="#style/app_theme" >
<service android:name="com.example.utilities.BluetoothServices"></service>
<activity
android:name="com.example.pkg.Thisisit"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
What is the problem in above code?Why it is not binding and calling method?
Order of operations. The order of lifecycle callbacks when the Activity starts is
onCreate()
onStart()
onResume()
In your code, you check if the Service is bound and call the send data method in onCreate(), but don't bind to the Service until onStart(), so your first block of code will never trigger since you are never bound at that point.
A couple other points to note:
Service binding is asynchronous. Even if you reorder your calls so SendData() were in onResume() the Service would still not likely be ready; the Service is not immediately bound after you call bindService(). That's what ServiceConnection is for, it tells you when the Service is available with the onServiceConnected() callback. You must wait for this before accessing anything.
When binding to a Service, you don't also have to start it. A bound Service is started on binding if it is not already running. In the above code, the call to startService() is superfluous.