5

I have been working on making USB connection specified in the link here and successfully implemented it. Its working fine accept it is frequently getting disconnected. I got to know from this link and this link that there is a bug in android OS that there is no broadcast event of USB connection event. I have implemented a receiver for getting USB disconnecting event which is not too much important. Also I refer this link to create stable connection with USB i.e. start data communication after USB connection without any loss. This whole thing is working fine when there is single activity or single screen in application.

For multiple screen this connection thing is having problem i.e. connection is not stable and I have multiple screen in application in which I can receive data via USB in any activity at any time. So I have 2 question which I am seeking answers of with some code if possible

  1. How can I make stable connection with device attached via serial USB in android over multiple screens
  2. How to get rid of this frequent disconnection problem in the application over multiple screens

Any help would be greatful

EDIT:

I am adding my service which is responsible for communication with usb and starts a thread for continuous receiving data

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.os.IBinder;
import arya.omnitalk.com.usb.R;
import arya.omnitalk.com.usb.constants.FileReadingWritingConstants;
import arya.omnitalk.com.usb.constants.GeneralConstant;
import arya.omnitalk.com.usb.constants.UsbDataWriterConstants;

import com.hoho.android.usbserial.driver.UsbSerialProber;

public class UsbCommunicationService extends Service{

    public static ArrayList<String> _dataArray = new ArrayList<String>();
    private Thread mCommunicationThread = null;

    private class ReadThread implements Runnable {
        @Override
        public void run() {

            while (mCommunicationThread!= null && !mCommunicationThread.isInterrupted()) {

                // Here I write code to parse data received via USB

                 }          
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();

        UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); // Creating object of usb manager
        UsbDataWriterConstants.driver = UsbSerialProber.acquire(manager); // Acquiring usb channel

        if (UsbDataWriterConstants.driver != null) {
            try {
                UsbDataWriterConstants.driver.open();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            try {
                ReadThread mReadThread = new ReadThread();
                mCommunicationThread = new Thread(mReadThread);
                mCommunicationThread.start();
            } catch (SecurityException e) {
                DisplayError(R.string.error_security);
                DisplayError(R.string.error_security);
            }
        }

    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        if (mCommunicationThread != null)
            mCommunicationThread.interrupt();
        super.onDestroy();
    }


}
Community
  • 1
  • 1
Abhinav Singh Maurya
  • 3,313
  • 8
  • 33
  • 51
  • You could go about it a few different ways. I would suggest that you create a service that handles the USB connection and have your activities communicate with USB via your service. – Luis Apr 06 '13 at 05:36
  • @Leco I am currently doing that thing but as soon as usb connected again it creates instance again and I am not getting data as because I am holding old instance – Abhinav Singh Maurya Apr 06 '13 at 09:46
  • Without seeing your code to understand you application logic, one thing that comes to mind is that you can make the launchMode of the activity you don't want reinstantiated "singleTask" in the manifest file (android:launchMode="singleTask" under the activity tag). See https://developer.android.com/guide/topics/manifest/activity-element.html#lmode – Luis Apr 06 '13 at 14:55
  • @Leco I did that already. check my edit I have added code of service which is communication via usb – Abhinav Singh Maurya Apr 08 '13 at 05:38
  • Have you read through the [developer docs](http://developer.android.com/guide/topics/connectivity/usb/accessory.html) any? Not sure if they may help any. Also what I did when using AOA for multiple screens is I use fragments where my `AOA_Activity extends Activity` and then my `mainActivity extends AOA_Activity` and from there my different fragments communicate via the `mainActivity`. Not sure if that helps any. – TronicZomB Apr 08 '13 at 17:46
  • @AbhinavSinghMaurya How do you start your service? – Luis Apr 08 '13 at 22:00
  • @TronicZomB I tried to do that also. I have created my application first in the manner you have explained but its was also not helping thats why I switched to service but its also not helping – Abhinav Singh Maurya Apr 09 '13 at 05:17
  • @Leco I have started this service as a normal service like Intent intent = new Intent(this, UsbCommunicationService.class); startService(intent); – Abhinav Singh Maurya Apr 09 '13 at 05:18

2 Answers2

0

You probably have disconnections because your service is only a bound service. First activity starts, bind to the service, which will then starts. When you switch to another activity, the first one is stopped, so it unbind. At this point, the service is not bound anymore, so it is killed. Bound services are explained here: http://developer.android.com/guide/components/bound-services.html

What you need is probably to keep the service running as long as USB is connected. To achieve that, you need a "persistent" service, a started one, as described here: http://developer.android.com/guide/components/services.html You can start your service in the onCreate of the activity that received the CONNECTED event, using:

public class HomeActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...
        Intent intent = new Intent(this, UsbCommunicationService.class);
        startService(intent);
        // ...
    }
}

The UsbCommunicationService will be started via this method (onStart() is deprecated):

public class UsbCommunicationService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        // TODO : connect to USB...

        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.       
        return START_STICKY;
    }
}

Next, all your activities can "bind", "unbind" and "rebind" to this service that will survive. Don't forget to stop it on DISCONNECT event, using:

stopSelf(); // Will actually stop AFTER all clients unbind... 
Pang
  • 9,564
  • 146
  • 81
  • 122
Bonrry
  • 434
  • 4
  • 5
  • please check my service code. I am doing exactly what you are showing here. its not helping – Abhinav Singh Maurya Apr 09 '13 at 05:16
  • You use onStart(Intent intent, int startId) instead of onStartCommand(...). So you can't return START_STICKY, and you service may not be a "started"+"bound" service surviving... Also to be sure not to be killed, your service must request foreground by adding a notification to the status bar. – Bonrry Apr 09 '13 at 07:58
  • On that note I can say my service is running all time. secondly I am stopping and starting service when ever it is necessary and my service gets starts and stopped when event provided so there is no issue related to service is not started or killed – Abhinav Singh Maurya Apr 09 '13 at 08:26
  • forgive me if I am wrong but I think this is not question related to service please read my question correctly and provide me answer accordingly. I am full aware of services and its functionality so I am in search answers related to android open accessories and its drawback removal technique. My service is running 100% in background when USB is connected/disconnected. But I am not getting events of USB connected so how can I get that event via code – Abhinav Singh Maurya Apr 09 '13 at 08:30
  • Yes but USB is not getting connected after disconnecting and I am unable to receive data after disconnection and reconnection – Abhinav Singh Maurya Apr 09 '13 at 08:44
  • The first question is: how to make stable connection, even between apps => proper use of service do this prefectly, I use it in my project. – Bonrry Apr 09 '13 at 08:47
  • For the second question, I may have misunderstood in my first reply... If I understand with your replies, your problem is that your device disconnect sometimes, but as you have multiple apps you loose the link? Only one (not two) Activity (not Service or Receiver) can be notified of the USB CONNECTED event. So personnaly I use a fake empty activity, fired on USB_ACCESSORY_CONNECTED event, and its only role is to start my service. The service, in onStartCommand(), check if it need to establish or re-establish the usb connection. – Bonrry Apr 09 '13 at 08:47
  • Ok it's a different question :), it's not related to multiple screens apps... I have the same if I stay on one screen, connected, then I kill my accessory (actually simulated on a PC). Even if all is properly closed accessory side, I don't get a DISCONNECT event on Android, unless I unplug the usb cable. If I restart the accesory, the flow restarts on Android. It seems that android doesn't close the accessory until the cable is unplug or the accessory make a usb reset. – Bonrry Apr 09 '13 at 09:11
  • Actually android fires disconnect event but not the connected event. and you can only get connection event on one screen i.e. launching screen of application. If I am having single screen in app its works like charm but having multiple screen creates problem. and its also bug in android so that is the problem – Abhinav Singh Maurya Apr 09 '13 at 09:14
  • OK i'll post you a second anwser :) – Bonrry Apr 09 '13 at 09:16
0

Here is the code of my Activity beeing registered for my USB accessory.

    public class UsbAccessoryAttachedWorkaroundActivity extends Activity {

    /**
     * Used only to catch the USB_ACCESSORY_ATTACHED event, has it is not broadcasted to 
     * anything else than the activity with the right accessory_filter (no Service, nor Receiver...)
     * DETACHED event is broadcasted as other events. 
     */

     @Override
     public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             Intent intent = new Intent(this, UsbService.class);
             startService(intent);
             finish(); // <- die ASAP, without displaying anything.
     }
    }

This way you get all CONNECT events as the activity is not still alive => Android relaunch it each time accessory is discovered... My Service starts my HomeActivity only if nobody is bound to it. If someone is bound, it means that a UI is already present, thus I just notify my listeners that the USB connection is back...

Bonrry
  • 434
  • 4
  • 5
  • Thanks for the code Bonrry but There is one more restriction I cannot relaunch same activity and I have to do this kind of stuff in background on some different activity :). This is what I ment to say in my asked questions – Abhinav Singh Maurya Apr 09 '13 at 11:15