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.
Related
I want to implement this scenario for my application. I want to schedule my service to start when the phone boots, and whenever another application calls my service I want my service to start a certain activity within the project.
So in order to be clear. I want to create a project which contains a service which runs whenever the phone boots, and is dormant, listening for a call from a third party application. And whenever that call is received this service calls an Activity (from the same project, not third party)
How can I configure my manifest file in order to achieve this?
I have also come across this suggestion but my scenario is pretty different.
Thank you very much in advance
**Define Service in manifest and Create the BroadcastReciever with boot complete permission and listen the intent.If boot completed start the service.**
public class MyService extends Service {
Context context = this;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Intent activity = new Intent(context, MyActivity.class);
activity.putExtra("Message", "fromService");
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(activity );
} catch (Exception e) {
MyLog.printException(e);
}
return super.onStartCommand(intent, flags, startId);
}
}
By creating a BroadcastReceiver you can perform the service startup.
public class StartupReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent(context, ShowActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
and in the manifest
<receiver
android:name=".StartupReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
This allows you to run an Activity, you can then start a Foreground Service from that activity. I just set this example because I have it ready, you can adapt it to run a service as you like.
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.
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);
I build a simple remote service with aidl file. The service and the activity are in two diferent virtual device. The service isn't reachable with an activity. I think the service doesn't start.
In DDMS view my service doen't appear and LogCat launch an error : unable to start service Intent { cmp = com.michelService.BIND pkg=com.michelService}: not found
THANKS for your help!
My AndroidManifest.xml :
*<?xml *version*="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.michelService"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="13" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<service android:name=".ServiceHello" android:exported="true" >
<intent-filter>
<action android:name="com.michelService.BIND"></action>
</intent-filter>
</service>
</application>
</manifest>*
My activity : CallServiceActivity.java :
public class CallServiceActivity extends Activity {
/** Called when the activity is first created. */
IServiceHello service;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
TextView tv1 = new TextView(this);
Intent intent = new Intent();
intent.setAction("com.michelService.BIND");
intent.setPackage("com.michelService");
startService(intent);
ServiceConnection con = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
service = IServiceHello.Stub.asInterface(binder);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
service= null;
}
};
bindService(intent, con, Context.BIND_AUTO_CREATE);
try {
tv1.setText(service.sayHello("Michel"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
tv1.setText("" + e);
}
layout.addView(tv1);
setContentView(layout);
}
}
The service and the activity are in two diferent virtual device.
It does not work then. You can use services only on the same device. If you want to communicate with a different device then you have to do that via network.
You probably want to start both on the same.
Remote service means "in a different Process" here. You use AIDL to access the other process. Different Processes are a bit like different devices since they don't share a common environment and the communication between them is also a bit like network communication.