How to implement Android Open Accessory mode as a

2019-03-17 02:34发布

问题:

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?

回答1:

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.



回答2:

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.