I've spent days trying to get the android ADK connection running in a service rather then activity..... Anyone know if its even possible?
I would like to have the service handled inputStream and outputStream so I can read my Arduino for extended periods in the background.
When the activity returns to focus I will bind with the service and update the GUI. If this is possible I would eventually like to update a website with the live data from the service for remote monitoring.
Any help if appreciated. I'm new to programming and can't seem to find much info on this topic.
Thank you in advace for the help.
I'm also trying it and I've found out this.
http://robotgrrl.com/blog/2011/11/29/android-adk-background-service/
I was able to get a ADK connection running in the following way (not complete code. Only the basic building blocks):
First I have an activity that the receives adk intent broadcasts (android system service bases on the adk meta data and the manifest).
private static final String USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent().getAction() != null && getIntent().getAction().equals(USB_ACCESSORY_ATTACHED)) {
Intent service = new Intent(this, ADKservice.class);
service.putExtras(getIntent());
startService(service);
Intent launch = new Intent(this, MainActivity.class);
launch.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(launch);
}
this.finish();
}
If the intent matches the adk string it will start the adk service and pass the intent information to the service, launch the user interface activity and finish itself.
The user interface (MainActivity) now binds to the service just like any other service so it can call public methods and/or receive data via the service callbacks (local broadcast's can also be used).
The ADKservice extends Runnable to monitor the usb connection. It also registers a receiver for adk disconnect so it can stop if the device gets disconnected:
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
mNotificationManager =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("ADK Service")
.setContentText("Started");
startForeground(notifyID, mBuilder.build());
super.onCreate();
}
After onCreate has finished the service will call onStartCommand where the adk initialization starts.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartup " + mAccessory );
mAccessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (mAccessory != null) {
openAccessory(mAccessory);
}
return super.onStartCommand(intent, flags, startId);
}
private void openAccessory(UsbAccessory accessory) {
Log.d(TAG, "openAccessory: " + accessory);
UsbManager mUsbManager = (UsbManager) getApplicationContext().getSystemService(Context.USB_SERVICE);
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
thread = new Thread(null, this, "ADKserviceThread");
thread.start(); // start runnable
}
public void run() {
// handle adk "usb" messages here
}
#Override
public void onDestroy() {
closeAccessory();
stopForeground(true);
super.onDestroy();
}
private void closeAccessory() {
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
}
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
closeAccessory();
stopSelf();
}
}
};
The handling of the connection might need some tweaks but the overall concept seems to work. I hope that helps everyone! It seems easy now but it took me a long time to here (I'm repetitively new to programming)
You should handle the loading of the accessory in the main activity like here, and then pass a reference to the accessory object to a service.
You can now bind the service from any activity and get access to the input/output streams.
You can also close the activity, and when you disconnect the accessory, the activity should catch the intent broadcast and relaunch to perform the closeAccessory routine.
Related
So, I have an app that starts a service. This service starts to scan for bluetooth devices with BTAdapter.startDiscovery(). Further I have a broadcastreceiver which listens for the DISCOVERY_FINISHED action. If that occurs I want to call a method from onReceive() in my service that starts the scanning process again. How am I gonna do this?
Here my receiver:
public class PollingReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ScanBTService sBTs = new ScanBTService();
sBTs.startScan();
}
}
and here the service:
public class ScanBTService extends IntentService {
private BluetoothAdapter mBTAdapter;
private PollingReceiver mPollingReceiver;
public ScanBTService() {
super("ScanBTService");
}
#Override
protected void onHandleIntent(Intent intent) {
final BluetoothManager btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBTAdapter = btManager.getAdapter();
mBTAdapter.startDiscovery();
}
public void startScan() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mBTAdapter.startDiscovery();
}
}
In your onReceive()-method, restart your service using the following two lines. I did not tested it out but it should work like that.
#Override
public void onReceive(Context context, Intent intent) {
//ScanBTService sBTs = new ScanBTService();
//sBTs.startScan();
Intent i = new Intent(getApplicationContext(), ScanBTService.class);
startService(i);
}
You can then remove the startScan()-method, too.
Try this to resolve the method:
context.startService(new Intent(context, SimpleWakefulService.class));
Since you are using an IntentService, you will need to create an intent for the started service to handle.
This can be achieved by the following :
Intent intent = new Intent(context, ScanBTService.class);
startService(intent);
As described here : https://developer.android.com/training/run-background-service/send-request.html
Now, if you are looking to have a service that maintains bluetooth connections, discover devices, send & receive data... If this is the case, then in my experience, i would argue the following points :
Perhaps the best way to go about this (depending on what you're doing of course), would be to have a service running in it's own separate process which would be responsible for all of that. Check : http://developer.android.com/guide/topics/manifest/service-element.html and the tag
android:process
Take advantage of Android's IPC communication feature to pass & receive messages between you're main app thread and your service. Tutorial : http://www.survivingwithandroid.com/2014/01/android-bound-service-ipc-with-messenger.html.
Create & Maintain connection quick guide : http://developer.android.com/guide/topics/connectivity/bluetooth.html#ConnectingAsAClient
Hope it helps
Cheers
My intention is to have download service created when the app first runs and checks for update every 24 hours. I originally had everything running my main activity but it seems to much to run everything on one thread and one class. So this is my attempt to move it to another class and into service. It suppose to run and check for an update ever 24 hours and if there is no internet try again in 4 hours. I specifically want to involve any recursive problems, having two or three same services checking update, just one every 24 hours. But having problem with integrating my code into service, what am I doing wrong?
public class DownloadService extends IntentService {
// TODO 0 - Define your Download Service as Android component in
// AndroidManifest.xml
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
#Override
protected void onHandleIntent(Intent intent) {
private final Runnable mUpdateUi = new Runnable(){
public void run(){
check();
}
};
private void start(){
new Thread(
new Runnable(){
public void run(){
Log.d(TAG, "inside start");
Looper.prepare();
mHandler = new Handler();
check();
Looper.loop();
}
}
).run();
}
private void check(){
if (isNetworkAvailable()== true){
try {
new checkupdate().execute();
delayTime = 86400000;
Toast.makeText(DownloadService.this, "Daily update check!", Toast.LENGTH_SHORT).show();
}
catch (IOException e) {
e.printStackTrace();
delayTime = 21600000;
}
}else{
delayTime = 21600000;
Toast.makeText(DownloadService.this, "No internet for Daily update check, try again in little!", Toast.LENGTH_SHORT).show();
}
reCheck();
}
private void reCheck(){
mHandler.postDelayed(mUpdateUi, delayTime);
}
}
IntentService already handles setting up a worker thread and queue, and termination when the queue is empty. Which makes it a very good candidate for something like a download service to manage the actual work of downloading data, but not really a great candidate for a time scheduler.
I'd suggest using an AlarmManager to schedule your work instead. What you want is to trigger an Intent to start your DownloadService, by sending it intent with an Action indicating what to do.
Note also that if you want to cancel an IntentService with an Action, you will need to implement onStartCommand in addition to the usual onHandleIntent, so that you can respond to the action immediately -- you cannot do this from onHandleIntent, since the intent won't be sent to that until the current task in the queue is completed. Here's a quick example:
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
////////////////////////////////////////////////////////////////////////
// Actions
public static final String ACTION_CANCEL = "package.name.DownloadService.action.CANCEL";
public static final String ACTION_DOWNLOAD = "package.name.DownloadService.action.DOWNLOAD";
////////////////////////////////////////////////////////////////////////
// Broadcasts
public static final String BROADCAST_DOWNLOADED = "package.name.DownloadService.broadcast.DOWNLOADED";
public static final String BROADCAST_ERROR = "package.name.DownloadService.broadcast.ERROR";
////////////////////////////////////////////////////////////////////////
// Extras
public static final String MESSAGE = "package.name.DownloadService.extra.MESSAGE";
// etc.
private boolean isCancelled;
// usual stuff omitted
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
String action = intent.getAction();
Log.v(TAG, "onStartCommand() - action: "+action);
if(ACTION_CANCEL.equals(action)) {
isCancelled = true;
// insert code here to signal any objects to cancel
// their work, etc.
stopSelf();
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent intent) {
if(intent != null) {
final String action = intent.getAction();
Log.v(TAG, "onHandleIntent() - action: "+action);
if(ACTION_DOWNLOAD.equals(action)) {
handleDownloading(intent);
}
else if(ACTION_CANCEL.equals(action)) {
// nothing to do here, handled in onStartCommand
}
}
}
////////////////////////////////////////////////////////////////////
private void handleDownloading(Intent intent) {
// get stuff you need from the intent using intent.getStringExtra(), etc.
if(!isCancelled) {
// do downloading, call broadcastDownloaded() when done
}
else {
// stop work, send broadcast to report cancellation, etc.
}
}
// send a broadcast to a BroadcastReceiver (e.g. in your activity)
// to report that the download completed
private void broadcastDownloaded() {
Log.v(TAG, "broadcastDownloaded()");
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_DOWNLOADED);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
private void broadcastError(String message) {
Log.v(TAG, "broadcastError(), message: "+message);
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_ERROR);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
if(message != null) {
broadcastIntent.putExtra(MESSAGE, message);
}
sendBroadcast(broadcastIntent);
}
}
}
This is not how IntentService is meant to be used. As per the documentation, IntentService already creates its own worker threads. You should not be creating your own:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Apart from the fact that your code as shown here won't compile (your start method is inside the onHandleIntent method), your general approach seems to be to start your own worker thread. What would happen in this approach is that you would start the thread, onHandleIntent would complete and then the service would be stopped. In addition to not actually working, this approach is also a bad idea because (at best if you're lucky) the service would be running continually 24/7.
What you should do instead is actually do your main work in onHandleIntent which IntentService will queue on a worker thread for you. Then instead of using postDelayed use AlarmManager to set an alarm to send an Intent to start the service again in 24 hours or 4 hours.
I've a problem with an app I'm coding.
I need to receive ACTION_SCREEN_ON, ACTION_SCREEN_OFF and ACTION_USER_PRESENT intents everytime they're broadcasted, so my app of course stays in background. At the moment my app is made by a settings activity and a service. ScreenReceiver is a BroadcastReceiver that gets the ACTION_SCREEN_* intents, while UnlockReceiver gets the ACTION_USER_PRESENT intent. The service registers and unregisters the receivers:
public class MainService extends Service {
ScreenReceiver screenReceiver = null;
UnlockReceiver unlockReceiver = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
doStart();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doStart();
return START_STICKY;
}
public void doStart() {
if(screenReceiver != null && unlockReceiver != null)
return;
IntentFilter filter;
if(screenReceiver == null) {
filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
screenReceiver = new ScreenReceiver();
registerReceiver(screenReceiver, filter);
}
if(unlockReceiver == null) {
filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_PRESENT);
unlockReceiver = new UnlockReceiver();
registerReceiver(unlockReceiver, filter);
}
}
#Override
public void onDestroy() {
if(screenReceiver != null)
unregisterReceiver(screenReceiver);
if(unlockReceiver != null)
unregisterReceiver(unlockReceiver);
}
}
But sometimes Android kills my service to free some RAM and then restarts it. The time between the kill and the respawn is usually around 5 seconds, but sometimes this can be enought to miss some intents causing problems to the users of my app. Those intents can be registered only trought registerReceiver, so I can't register them in the manifest. How could I listen to those intents without being killed or missing some?
Thanks!
How could I listen to those intents without being killed or missing some?
You don't. You rewrite your app to either not use those broadcasts or to be more resilient in the case of missing broadcasts. After all, it is not just "Android kills my service to free some RAM and then restarts it", but task managers and the like that can get rid of your service.
I've been playing around with the Android Open Accessory Development Kit. By following the DemoKit example provided by Google, I've had no trouble in adapting the solution to my application. I can detect, communicate, and detach the accessory just fine.
However, I would need to run the whole thing as a service. I have a base activity which is launched by the USB_ACCESSORY_ATTACHED intent (that is, when the accessory is connected), and that works fine. But as soon as I start my service and run identical code in it compared to my working solution within a regular activity, I'm receiving an IOException ("no such device") whenever I'm trying to communicate with the accessory (monitoring arduino side shows a successful USB connection). This happens even though I've specified the correct BroadcastReceiver within the service, registered it in the onStartCommand callback method, and set up the communication endpoints with openAccessory(). Relevant code is as follows.
#Override
public void onCreate() {
Log.d(TAG, "ONCREATE");
manager = UsbManager.getInstance(this);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
ACTION_USB_PERMISSION), 0);
// Register broadcastreceiver for filtering accessory events
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver,filter);
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "ONSTARTCOMMAND METHOD ACCESSED");
if (mInputStream != null && mOutputStream != null) {
return START_NOT_STICKY;
}
UsbAccessory[] accessories = manager.getAccessoryList();
mAccessory = (accessories == null ? null : accessories[0]);
if (mAccessory != null) {
if (manager.hasPermission(mAccessory)) {
openAccessory();
} else {
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
manager.requestPermission(mAccessory,
mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
} else {
Log.d(TAG, "mAccessory is null");
}
return START_NOT_STICKY;
}
openAccessory method:
/**
* Open the accessory
*/
private void openAccessory() {
Log.d(TAG, "openAccessory: "+mAccessory);
mFileDescriptor = manager.openAccessory(mAccessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null,this,"AccessoryThread");
thread.start();
}
}
Any ideas for a possible solution?
The solution was simple.
if (intent.getAction().equals(USB_ACCESSORY_ATTACHED)) {
Intent i = new Intent(this, YourServiceName.class);
i.putExtras(intent);
startService(i);
}
Basically, copy the intent that you received when starting your activity that you use to launch the service, because the intent contains the details of the accessory that the ADK implementation needs.
Then, in the service proceed to implement the rest of ADK exactly as before.
At the moment I can't give you a matching solution to your problem. But may be this
github example shows you how to solve your problem:
I am going to analyse the code given on github to implement just the same thing you're going to do.
I have an app in which I'm trying to detect WHEN the Internet connection appears and when it disappears.
At the moment, when it appears, I'm starting a new thread (different from the UI) which connects my app to a remote server.
For that I'm hardly trying to implement a broadcast receiver which LISTENS for connectivity, but I'm having problems in understanding the concept.
In my onCreate() I have somethig like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
cThread.start();
}
When there is connection to the Internet I'm sending data through the socket, when there is not I'm storing the data in a database. And when the Internet appears I'm restarting my thread to reconnect and send the old data (which hasn't been sent because of network crashing) and the new one.
Let's say I would implement something like this:
DoRefreshBroadcastReceiver refreshBroadcastReceiver;
...
onResume() {
// register the refreshing complete broadcast receiver
IntentFilter intentFilter = new IntentFilter(DO_REFRESH);
refreshBroadcastReceiver = new doRefreshBroadcastReceiver();
registerReceiver(refreshBroadcastReceiver, intentFilter);
}
public class DoRefreshBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// call method to run fetch code...
}
}
Does this mean that when the Internet connection is detected my onReceive() gets called? And I could start my thread there?
What is the concept of using an intent? Because I really don't get it. How to use it, and what its purpose?
THE IDEA: I don't really know how to use this intent in this case or how to use it in my app!
Would this thing detect the connection to the Internet even when I'm not in this activity?
EDIT:
Here is how my onReceive looks like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
// cThread.start();
connIntentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
public void onReceive(Context context, Intent intent)
{
mNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (mNetworkInfo != null && mNetworkInfo.isConnected())
{
/*
* if(mNetworkInfo.getType()==ConnectivityManager.TYPE_WIFI);
*
*
* else
*/
cThread.start();
}
else {
System.out.println("There is no internet connection!");
try {
cThread.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
mNetworkInfo != null && mNetworkInfo.isConnected()
Does this mean it's connected or should I verify for a certain type of connection on the emulator?
*I think that I should start my thread directly in onReceive(). As soon as my app starts it detects the Internet connection and BroadcastReceiver gets fired, doesn't it?
Try something like this...
public class MyActivity extends Activity {
private MyConnectivityListener connListener = null;
private IntentFiler connIntentFilter = null;
private Boolean connIntentFilterIsRegistered = false;
#Override
protected void onCreate(...) {
...
connIntentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
#Override
protected void onResume() {
...
if (!connIntentFilterIsRegistered) {
registerReceiver(connListener, connIntentFilter);
connIntentFilterIsRegistered = true;
}
}
#Override
protected void onPause() {
...
if (connIntentFilterIsRegistered) {
unregisterReceiver(connListener);
connIntentFilterIsRegistered = false;
}
}
protected class MyConnectivityListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// The NetworkInfo for the affected network is sent
// as an extra; it should be consulted to see what
// kind of connectivity event occurred.
}
}
}
A BroadcastReceiver is effectively a 'listener' which listens for events either sent by the system or, in some cases, by your own application components.
In this case, the system broadcasts android.net.conn.CONNECTIVITY_CHANGE whenever there is a connection change (connected/disconnected). By registering your BroadcastReceiver to 'listen' for that event, you can get the extra included in the Intent from your BroadcastReceiver's onReceive(...) method and do whatever you need to do accordingly. The extra is a `NetworkInfo object which will contain information about the particular network and whether it is connected or not.