I am trying to build a remote service to which I can bind to activities that will be used and created often. I think this is the best method for handling what it is I am trying to accomplish. I keep getting this error though.
Unable to start service Intent { act=com.services.OverheadService } U=0: not found
I would think something might be wrong with my manifest? But I don't see what, my manifest will be at the bottom of the related code here below.
Here is the Call within my onCreate() in my activity:
// TESTING SERVICE IMPLMENTATION TODO
Intent serviceIntent = new Intent("com.services.OverheadService");
boolean ok = this.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.v("ok", String.valueOf(ok));
Here is the Connection method:
/** SERVICE IMPLEMENTATION TESTING **/
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// get instance of the aidl binder
mRemoteService = IRemoteService.Stub.asInterface(service);
try {
String message = mRemoteService.sayHello("Mina");
Log.v("message", message);
} catch (RemoteException e) {
Log.e("RemoteException", e.toString());
}
}
};
And here is the Service Class:
package com.services;
import com.services.IRemoteService.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class OverheadService extends Service {
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
// implementation of the aidl interface
private final IRemoteService.Stub mBinder = new Stub() {
#Override
public String sayHello(String message) throws RemoteException {
return "Hello " + message;
}
};
}
AndroidManifest where the service is being set:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<service
android:name="com.services.OverheadService"
android:enabled="true"
android:icon="#drawable/failed_load" >
<!--
intent-filter>
<action android:name="com.cdkdevelopment.BaseActivity" />
</intent-filter>
-->
</service>
I have found the solution and it was changing this in the onCreate
Intent serviceIntent = new Intent(this, OverheadService.class);
boolean ok = this.getApplicationContext().bindService(serviceIntent,
mServiceConnection, Context.BIND_AUTO_CREATE);
Log.v("ok", String.valueOf(ok));
Related
I have an Android app that specifies two AIDL files and a service. This service should be used from another app to invoke the methods defined on the AIDL. I have followed the Android Documentation on AIDL to implement the AIDL files and the service (see the code below).
Then I created a very simple client app (also shown below) to bind to the service and invoke the method defined on my AIDL file. However, the bindService always returns false and mentions that the intent cannot be found. These are some things I tried to correctly reference the intent on the client side:
Intent intent = new Intent("a.b.c.service");
intent.setPackage("a.b.c");
---
Intent intent = new Intent("service");
intent.setPackage("a.b.c");
---
Intent intent = new Intent();
intent.setClassName("a.b.c", "a.b.c.services.MyService");
---
Intent intent = new Intent();
intent.setClassName("a.b.c.services", "a.b.c.services.MyService");
---
Intent intent = new Intent();
intent.setClassName("a.b.c", ".services.MyService");
---
Intent intent = new Intent();
intent.setAction("service");
intent.setPackage("a.b.c");
intent.setClassName("a.b.c", ".services.MyService");
---
Intent intent = new Intent();
intent.setAction("service");
intent.setClassName("a.b.c", ".services.MyService");
If I try from the same application where the service resides, I can use the following and it will work:
Intent intent = new Intent(this, MyService.class);
But since this is a remote service, I do not have access to MyService class from the client app, so I can't find any way of making it work.
I have wondered through a lot of StackOverflow posts without any luck. Examples:
Android: Binding to a remote service
How can I use AIDL remote service to deal with defferent clients' concurrent requests?
Android Bind Service returns false every time
How should I specify my intent in this case?
Thanks in advance.
Relevant code:
IServiceInterface.aidl
package a.b.c;
import a.b.c.IServiceInterfaceGetStuffCallback;
interface IServiceInterface
{
void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback);
}
IServiceInterfaceGetStuffCallback
package a.b.c;
interface IServiceInterfaceGetStuffCallback
{
void onGetStuffResponse(String arg1, boolean arg2, int arg3, int arg4);
}
a.b.c./services/MyService.java
public class MyService extends Service
{
private final MyService self = this;
private MyServiceHandler handler = null;
private final HandlerThread handlerThread = new HandlerThread("AidlServiceThread");
//Callbacks
private final ArrayList<IServiceInterfaceGetStuffCallback> getStuffCallbacks = new ArrayList<>();
private final int MY_SERVICE_GET_STUFF_MSG = 1;
public MyService()
{
}
#Override
public IBinder onBind(Intent intent)
{
// Handler Thread handling all callback methods
handlerThread.start();
handler = new MyServiceHandler(handlerThread.getLooper());
return mBinder;
}
IServiceInterface.Stub mBinder = new IServiceInterface.Stub()
{
#Override
public void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback) throws RemoteException
{
//Register the callback internally
getStuffCallbacks.add(callback);
final int cbIndex = getStuffCallbacks.size() - 1;
getStuff((arg1, arg2, arg3, arg4) ->
{
MyServiceResponse response = new MyServiceResponse();
response.arg1 = arg1;
response.arg2 = arg2;
response.arg3 = arg3;
response.arg4 = arg4;
Message message = handler.obtainMessage();
message.arg1 = cbIndex;
message.obj = response;
message.what = MY_SERVICE_GET_STUFF_MSG;
handler.sendMessage(message);
});
}
};
private class MyServiceHandler extends Handler
{
int callbackIndex = 0;
MyServiceHandler (Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
callbackIndex = msg.arg1;
MyServiceHandler response = (MyServiceHandler)msg.obj;
switch (msg.what)
{
case MY_SERVICE_GET_STUFF_MSG:
{
try
{
getStuffCallbacks.get(callbackIndex).onGetStuffResponse(response.arg1, response.arg2, response.arg3, response.arg4);
}
catch (RemoteException e)
{
e.printStackTrace();
}
break;
}
default:
break;
}
}
}
private static class MyServiceResponse
{
public String arg1;
public boolean arg2;
public int arg3;
public int arg4;
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="a.b.c">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<permission
android:name="a.b.c.myservice"
android:protectionLevel="signature" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|keyboard|colorMode|density|navigation|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize|touchscreen|uiMode">
(...)
<service
android:name="a.b.c.services.MyService"
android:enabled="true"
android:exported="true"
android:permission="a.b.c.myservice">
<intent-filter>
<action android:name="a.b.c.myservice" />
</intent-filter>
</service>
</application>
</manifest>
Client app - MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
private final String TAG = "aidltest";
MainActivity self = this;
IServiceInterface service = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_get_stuff).setOnClickListener(this);
}
#Override
public void onClick(View view)
{
if (view.getId() == R.id.btn_get_stuff)
getStuff();
}
void getStuff()
{
Log.e(TAG, "getStuff invoked");
Intent intent = new Intent("a.b.c.myservice");
intent.setPackage("a.b.c");
boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "Service binding result: " + res);
}
private ServiceConnection serviceConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
self.service = IServiceInterface.Stub.asInterface(service);
Log.e(TAG, "ServiceInterface attached");
}
public void onServiceDisconnected(ComponentName className)
{
service = null;
Log.e(TAG, "Service disconnected");
}
};
}
The following changes work for me:
Adjust your manifest as follows:
<service
android:name="a.b.c.services.MyService"
android:enabled="true"
android:exported="true"
android:permission="a.b.c.myservice">
<intent-filter>
<action android:name="a.b.c.myservice" />
<category android:name="android.intent.category.DEFAULT"/> <---- NEW LINE
</intent-filter>
</service>
Run adb shell pm list packages and get the package id of the apk where you declared the service. This is needed for building the intent in step 3. Let's call it PACKAGE_ID.
Adjust the getStuff method as follows:
void getStuff() {
Log.e(TAG, "getStuff invoked");
Intent intent = new Intent("a.b.c.myservice"); // This is the value you used in the action for your service as declared in the manifest.
intent.setPackage(PACKAGE_ID); // This is the value you retrieved in step 2.
boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "Service binding result: " + res);
}
I am trying to develop a setup of 2 applications (service app + client app) using AIDL. I have currently a setup of 3 modules:
android-agent-framework (android library module holding only the AIDL file)
android-agent (the service)
android-example-client (the client)
android-agent and android-agent-framework have a dependency to the first one to get access to the interface.
Whenever the client calls bindService() it gets false as return and in the ServiceConnection the onServiceConnected() is not called. Also in the service implementation the onBind() is not called. There is no error in the logs.
Here is the code:
android-agent activity:
public class MyCompanyStartActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(MyCompanyStartActivity.class.toString(), "Create MyCompanyStartActivity");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ComponentName service = startService(new Intent(this, MyCompanyRequestService.class));
Log.i("tag", service.getClassName() + "::" + service.getPackageName());
}
}
android-agent service:
public class MyCompanyRequestService extends Service {
#Override
public IBinder onBind(Intent intent) {
Log.i(MyCompanyRequestService.class.toString(), "Starting SmartRest Service");
return mBinder;
}
private final IMyCompanyRequestService.Stub mBinder = new IMyCompanyRequestService.Stub() {
#Override
public void sendData(String xid, String authentication, String data) throws RemoteException{
Log.i(MyCompanyRequestService.class.toString(), "sending data: " + data);
}
};
}
android-agent manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.android.agent" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MyCompanyStartActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Services -->
<service
android:name="com.mycompany.android.agent.framework.MyCompanyRequestService"
android:process=":remote"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="MyCompanyRequestService"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
<!-- Permissions -->
</application>
</manifest>
android-example-client activity:
public class ClientStarter extends Activity {
protected IMyCompanyRequestService mycompanyRequestService = null;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i("tag","create client");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
if (mycompanyRequestService == null) {
printServices();
Intent it = new Intent("MyCompanyRequestService");
it.setPackage("com.mycompany.android.agent.framework");
Log.i("tag","before binding service: " + it.getAction() + "::" + it.getPackage());
boolean serviceBinding = getApplicationContext().bindService(it, connection, Context.BIND_AUTO_CREATE);
Log.i("tag", "service is bound: " + serviceBinding);
}
Handler handler = new Handler();
handler.postDelayed(new Runner(), 10000);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("service", "Service connected");
mycompanyRequestService = IMyCompanyRequestService.Stub.asInterface(service);
Toast.makeText(getApplicationContext(), "Service Connected", Toast.LENGTH_SHORT).show();
Log.i("service", "Service connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i("service", "Service disconnected");
mycompanyRequestService = null;
Toast.makeText(getApplicationContext(), "Service Disconnected", Toast.LENGTH_SHORT).show();
Log.i("service", "Service disconnected");
}
};
private void printServices() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
Log.d("service", service.service.getClassName());
}
}
private class Runner implements Runnable {
#Override
public void run() {
Log.i("tag","starting");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Location loc;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Log.e(ClientStarter.class.toString(), "Error", e);
} while(true) {
try {
if (mycompanyRequestService != null) {
loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Log.i(ClientStarter.class.toString(), loc.getLatitude() + " - " + loc.getLongitude() + " - " + loc.getAltitude());
mycompanyRequestService.sendData("test", "auth", String.valueOf(loc.getLatitude()) + "," + String.valueOf(loc.getLongitude()) + "," + String.valueOf(loc.getAltitude()));
} else {
Log.i(ClientStarter.class.toString(), "service not yet available");
}
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.e(ClientStarter.class.toString(), "Error", e);
} catch (RemoteException e) {
Log.e(ClientStarter.class.toString(), "Error", e);
}
}
}
}
}
The printServices() call before trying to bind the service actually lists the service so it is running.
The log does not contain any errors and the client is in the end running in the loop but the service is still null.
Maybe someone encountered a similar issue before.
After going another round through all files I found my mistake.
I needed to change:
Intent it = new Intent("MyCompanyRequestService");
it.setPackage("com.mycompany.android.agent.framework");
to:
Intent it = new Intent("MyCompanyRequestService");
it.setPackage("com.mycompany.android.agent");
The package of the Intent needs to match the package of the app and not the package of the service.
Another reason why you could face this issue (at least I did) is that – from API level 30 – you are also required to declare the apps that you communicate to in the manifest, for example:
<queries>
<package android:name="com.your.app" />
</queries>
I use signalR lib in my project. but I was not able to compile libs of https://github.com/SignalR/java-client on my own - I found them in internet. But it seems like there are not full (WebsocketTransport is missing)
When I compile https://github.com/SignalR/java-client, i get two libs, and paste them to my app.gradle -
compile files ('libs/signalr-client-sdk.jar')
compile files ('libs/signalr-client-sdk-android.jar')
Progects build suckesfully, butwhen I press run - it fails.
Here is stack trace -
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
at com.android.dx.command.dexer.Main.processClass(Main.java:704)
at com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)
at com.android.dx.command.dexer.Main.access$300(Main.java:83)
at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)
at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
at com.android.dx.command.dexer.Main.processOne(Main.java:632)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:280)
at com.android.dx.command.dexer.Main.run(Main.java:246)
at com.android.dx.command.dexer.Main.main(Main.java:215)
at com.android.dx.command.Main.main(Main.java:106)
...while parsing microsoft/aspnet/signalr/client/Action.class
1 error; aborting
Error:Execution failed for task ':app:preDexDebug'.
com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0_45\bin\java.exe'' finished with non-zero exit value 1
I do not know what to do. I even tried to compile forks of this project, but have got the same result, same error. Need any help, Thanks!
UPDATE
in my Application class i have
Platform.loadPlatformComponent(new AndroidPlatformComponent());
in my app.gradle:
compile files ('libs/gson-2.2.2.jar')
compile files ('libs/signalr-client-sdk.jar')
compile files ('libs/signalr-client-sdk-android.jar')
in my code I use
connection.start(new ServerSentEventsTransport(connection.getLogger())).get();
I also create lots of hubs on this connection, nad call methods. All works, but connection always dissapears, if i do not do anything with device more then for 30 seconds. And I do not have any callbacks that the connection was lost\disconected or anything like that - I log all this stuff. But I think it can happen because i have pretty old libs, i googled - as I mention in this question i did not menaged to build signalR project to receive more recent libs
Here is my working basic code, hope this helps!
package com.example.simplesignalrclient;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import java.util.concurrent.ExecutionException;
import microsoft.aspnet.signalr.client.Credentials;
import microsoft.aspnet.signalr.client.Platform;
import microsoft.aspnet.signalr.client.SignalRFuture;
import microsoft.aspnet.signalr.client.http.Request;
import microsoft.aspnet.signalr.client.http.android.AndroidPlatformComponent;
import microsoft.aspnet.signalr.client.hubs.HubConnection;
import microsoft.aspnet.signalr.client.hubs.HubProxy;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler1;
import microsoft.aspnet.signalr.client.transport.ClientTransport;
import microsoft.aspnet.signalr.client.transport.ServerSentEventsTransport;
public class SignalRService extends Service {
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder(); // Binder given to clients
public SignalRService() {
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
#Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
startSignalR();
return mBinder;
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
/**
* method for clients (activities)
*/
public void sendMessage(String message) {
String SERVER_METHOD_SEND = "Send";
mHubProxy.invoke(SERVER_METHOD_SEND, message);
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
Credentials credentials = new Credentials() {
#Override
public void prepareRequest(Request request) {
request.addHeader("User-Name", "BNK");
}
};
String serverUrl = "http://192.168.1.100";
mHubConnection = new HubConnection(serverUrl);
mHubConnection.setCredentials(credentials);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
String HELLO_MSG = "Hello from Android!";
sendMessage(HELLO_MSG);
String CLIENT_METHOD_BROADAST_MESSAGE = "broadcastMessage";
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler1<CustomMessage>() {
#Override
public void run(final CustomMessage msg) {
final String finalMsg = msg.UserName + " says " + msg.Message;
// display Toast message
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
, CustomMessage.class);
}
}
Activity:
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private SignalRService mService;
private boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(mContext, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
public void sendMessage(View view) {
if (mBound) {
// Call a method from the SignalRService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
EditText editText = (EditText) findViewById(R.id.edit_message);
if (editText != null && editText.getText().length() > 0) {
String message = editText.getText().toString();
mService.sendMessage(message);
}
}
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private final ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to SignalRService, cast the IBinder and get SignalRService instance
SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
CustomMessage Class:
public class CustomMessage {
public String UserName;
public String Message;
}
JUST TO HELP SOMEONE WHO GOT STUCK LIKE ME.
I was trying to get my SingalR to work.
I followed the answer given but service was not firing.
This was my first project to implement a service like SignalRService.
So I did not know.
I added <service> entry to my manifest file then everything started working.
<service android:name=".SignalRService"
android:enabled="true"
android:exported="true">
</service>
Thanks a lot BNK
I am having trouble with this and can't get this to work. This is the code for empty main category launcher activity that has to show splash screen if service not running or user not authenticated else start conversations activity.
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
public class EntryPoint extends Activity {
private IAppManager imService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((IMService.IMBinder) service).getService();
// this is not starting activity :(
// Start converstion activity if service running and user ok
if (imService.isUserAuthenticated() == true) {
try {
Intent i = new Intent(EntryPoint.this, Conversations.class);
startActivity(i);
finish();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// this is not working
// start login activity if service disconnected
public void onServiceDisconnected(ComponentName className) {
imService = null;
try {
Intent intent = new Intent(getBaseContext(), Splash.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
finish();
} catch (Exception e) {
e.printStackTrace();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Start and bind the imService
startService(new Intent(EntryPoint.this, IMService.class));
}
#Override
protected void onPause() {
super.onPause();
try {
unbindService(mConnection);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onResume() {
super.onResume();
try {
bindService(new Intent(EntryPoint.this, IMService.class),
mConnection, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
When I run app, neither Conversations is run nor Splash activity is run but instead I see empty activity :( There is no error also, just empty EntryPoint activiy is run which should actually launch one of other activities.
Does anyone know what I am doing wrong here ?
Most probably your service is not connected and thus not able to interact with your activity.
Create an intent separately and then assign it at startService & bindService, instead of creating a new instance of intent every time for startService & bindService.
Also why are you binding the service at onResume()? Check this link out on why you should try to avoid this if possible - Binding to Service in onCreate() or in onResume()
Intent serviceIntent = new Intent(EntryPoint.this, IMService.class);
startService(serviceIntent);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
I want to test my bound service with ServiceTestCase.
The testing consists of binding to MyBindServer, and sending a Message.
Watching the logs, you can see the service is started when onBind() is called,
and a message is sent from testAHello(), but, the server's handleMessage() is never called.
From the logs:
I/TestRunner( 2099): started: testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
I/MyBindServerTest( 2099): setUp()
I/MyBindServer( 2099): onBind, action=com.inthinc.mybindserver.START
I/MyBindServerTest( 2099): testAHello
I/MyBindServerTest( 2099): sending SAY_HELLO
[here is where I expect to see the output from handleMessage()]
I/MyBindServerTest( 2099): tearDown()
I/TestRunner( 2099): finished:testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
I/TestRunner( 2099): passed: testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
Here is the code for MyBindServer.java:
package com.inthinc.mybindserver;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
public class MyBindServer extends Service {
static final String TAG = "MyBindServer";
public static final int MSG_SAY_HELLO = 1;
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.i(TAG, String.format("handleMessage, what=%d", msg.what));
switch (msg.what) {
case MSG_SAY_HELLO:
Log.i(TAG, "hello");
break;
default:
super.handleMessage(msg);
}
}
}
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG, String.format("onBind, action=%s", intent.getAction()));
return mMessenger.getBinder();
}
}
Here is the code for MyBindServerTest.java:
package com.inthinc.mybindserver.test;
import com.inthinc.mybindserver.MyBindServer;
import android.content.Intent;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.test.ServiceTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
public class MyBindServerTest extends ServiceTestCase<MyBindServer> {
private static final String TAG = "MyBindServerTest";
Messenger mServer = null;
public MyBindServerTest() {
super(MyBindServer.class);
}
public MyBindServerTest(Class<MyBindServer> serviceClass) {
super(serviceClass);
}
#Override
public void setUp() {
try {
super.setUp();
Log.i(TAG, "setUp()");
Intent bindIntent = new Intent("com.inthinc.mybindserver.START");
IBinder binder = bindService(bindIntent);
assertNotNull(binder);
mServer = new Messenger(binder);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void tearDown() {
try {
super.tearDown();
Log.i(TAG, "tearDown()");
} catch (Exception e) {
e.printStackTrace();
}
}
#SmallTest
public void testAHello() {
Log.i(TAG, "testAHello");
assertNotNull(mServer);
Message msg = Message.obtain(null, MyBindServer.MSG_SAY_HELLO);
Log.i(TAG, "sending SAY_HELLO");
try {
mServer.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
I was able to get this working using the procedure below..anyone is welcome to chime in if this is incorrect, but the example above works (i.e. MyBindServer's handler receives messages)
It seems as though ServiceTestCase's bindService() method intends to act like a local service. In this case, the goal is to test as a separate process, which means using the following instead of ServiceTestCase's bindService:
Intent bindIntent = new Intent(<registered intent>); //Where registered intent is declared in the manifest file
getContext().bindService(bindIntent,mConn,Context.BIND_AUTO_CREATE);
where mConn is a ServiceConnection object implemented to do whatever your test needs it to do, in the case above, set mServer.
With the above, MyBindServer's handleMessage() is called for the testAHello() test.
UPDATE: I have noticed that depending on how quickly the test processing is done, teardown() can be called before the binding is ready to use. In the case above adding control variables to throttle the program flow based on mConn's onServiceConnected being called provided consistent results.
E.g.
protected boolean bound = false;
protected boolean processed = false;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
Log.i(TAG,"Service conn");
mServer = new Messenger(service);
if(mServer != null
&& mServer != null){
bound = true;
}
processed = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.i(TAG,"Service Disconn");
}
};
Then add:
while(!processed){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
to testAHello()