Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Android Open Accessory mode as a 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?

like image 358
Petteri Pertola Avatar asked Oct 24 '22 20:10

Petteri Pertola


1 Answers

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.

like image 97
Petteri Pertola Avatar answered Oct 27 '22 11:10

Petteri Pertola