]> sigrok.org Git - sigrok-androidutils.git/commitdiff
UsbHelper: Add additional methods for device enumeration and monitoring
authorMarcus Comstedt <redacted>
Sun, 27 Nov 2016 14:56:24 +0000 (15:56 +0100)
committerUwe Hermann <redacted>
Sat, 3 Dec 2016 18:42:17 +0000 (19:42 +0100)
In newer Android versions, the native enumeration code use by
libusb does not work anymore due to the necessary virtual file
system nodes not being available to user processes. Therefore,
Java helper code is now needed for enumeration as well.

This fixes parts of bug #701.

src/org/sigrok/androidutils/UsbEventListener.java [new file with mode: 0644]
src/org/sigrok/androidutils/UsbEventListenerStub.java [new file with mode: 0644]
src/org/sigrok/androidutils/UsbEventMonitor.java [new file with mode: 0644]
src/org/sigrok/androidutils/UsbHelper.java
src/org/sigrok/androidutils/UsbSupplicant.java

diff --git a/src/org/sigrok/androidutils/UsbEventListener.java b/src/org/sigrok/androidutils/UsbEventListener.java
new file mode 100644 (file)
index 0000000..18876cd
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the sigrok-androidutils project.
+ *
+ * Copyright (C) 2016 Marcus Comstedt <marcus@mc.pp.se>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sigrok.androidutils;
+
+public interface UsbEventListener
+{
+       public void onUsbDeviceAction(String name, boolean removed);
+}
diff --git a/src/org/sigrok/androidutils/UsbEventListenerStub.java b/src/org/sigrok/androidutils/UsbEventListenerStub.java
new file mode 100644 (file)
index 0000000..d677c86
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the sigrok-androidutils project.
+ *
+ * Copyright (C) 2016 Marcus Comstedt <marcus@mc.pp.se>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sigrok.androidutils;
+
+final class UsbEventListenerStub implements UsbEventListener
+{
+       public native void onUsbDeviceAction(String name, boolean removed);
+}
diff --git a/src/org/sigrok/androidutils/UsbEventMonitor.java b/src/org/sigrok/androidutils/UsbEventMonitor.java
new file mode 100644 (file)
index 0000000..2ca5d63
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the sigrok-androidutils project.
+ *
+ * Copyright (C) 2016 Marcus Comstedt <marcus@mc.pp.se>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sigrok.androidutils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+import android.util.Log;
+
+final class UsbEventMonitor
+{
+       private final Context context;
+       private final UsbManager manager;
+       private final UsbEventListener listener;
+       private final BroadcastReceiver permReceiver;
+       private final BroadcastReceiver hotplugReceiver;
+       private final IntentFilter permFilter;
+       private final IntentFilter hotplugFilter;
+
+       UsbEventMonitor(Context context, UsbManager manager, UsbEventListener listener)
+       {
+               this.context = context;
+               this.manager = manager;
+               this.listener = listener;
+               permReceiver = new BroadcastReceiver() {
+                       @Override
+                       public void onReceive(Context context, Intent intent) {
+                               String action = intent.getAction();
+                               if (UsbSupplicant.ACTION_USB_PERMISSION.equals(action)) {
+                                       permissionCallback((UsbDevice)intent.getParcelableExtra(
+                                               UsbManager.EXTRA_DEVICE), intent.getBooleanExtra(
+                                               UsbManager.EXTRA_PERMISSION_GRANTED, false));
+                               }
+                       }
+               };
+               hotplugReceiver = new BroadcastReceiver() {
+                       @Override
+                       public void onReceive(Context context, Intent intent) {
+                               if (intent != null && UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+                                       attachCallback((UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
+                               } else if (intent != null && UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
+                                       detachCallback((UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE));
+                               }
+                       }
+               };
+               permFilter = new IntentFilter(UsbSupplicant.ACTION_USB_PERMISSION);
+               hotplugFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+               hotplugFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+       }
+
+       synchronized void start()
+       {
+               context.registerReceiver(permReceiver, permFilter);
+               context.registerReceiver(hotplugReceiver, hotplugFilter);
+       }
+
+       synchronized void stop()
+       {
+               context.unregisterReceiver(hotplugReceiver);
+               context.unregisterReceiver(permReceiver);
+       }
+
+       private void permissionCallback(UsbDevice dev, boolean granted)
+       {
+               Log.d("UsbEventMonitor", "permission " +
+                     (granted ? "granted" : "denied") + " for device " + dev);
+               addRemoveDevice(dev, !granted);
+       }
+
+       private void attachCallback(UsbDevice dev)
+       {
+               Log.d("UsbEventMonitor", "device " + dev + "added");
+               if (manager.hasPermission(dev))
+                       addRemoveDevice(dev, false);
+       }
+
+       private void detachCallback(UsbDevice dev)
+       {
+               Log.d("UsbEventMonitor", "device " + dev + "removed");
+               addRemoveDevice(dev, true);
+       }
+
+       private synchronized void addRemoveDevice(UsbDevice dev, boolean removed)
+       {
+               listener.onUsbDeviceAction(dev.getDeviceName(), removed);
+       }
+}
index e16b33d7242fcc6ef40f4d52351cfdface668ccd..cfa2aa992155e82746ae65aa0c12a3821638b1fb 100644 (file)
@@ -29,9 +29,12 @@ import java.util.HashMap;
 public final class UsbHelper
 {
        private static UsbManager manager;
+       private static Context context;
+       private static UsbEventMonitor eventMonitor;
 
        public static void setContext(Context ctx)
        {
+               context = ctx;
                if (ctx == null)
                        manager = null;
                else
@@ -54,6 +57,45 @@ public final class UsbHelper
                return (conn == null ? -1 : conn.getFileDescriptor());
        }
 
+       private static synchronized void startEventMonitor(Context context, UsbManager manager, UsbEventListener listener)
+       {
+               if (eventMonitor != null) {
+                   eventMonitor.stop();
+                   eventMonitor = null;
+               }
+               if (context == null) {
+                       Log.w("UsbHelper", "no context");
+                       return;
+               }
+               if (manager == null) {
+                       Log.w("UsbHelper", "no manager");
+                       return;
+               }
+               eventMonitor = new UsbEventMonitor(context, manager, listener);
+               eventMonitor.start();
+       }
+
+       private static synchronized void stopEventMonitor(Context context)
+       {
+               if (eventMonitor != null) {
+                   eventMonitor.stop();
+                   eventMonitor = null;
+               }
+       }
+
+       private static String[] scanDevices(UsbManager manager)
+       {
+               if (manager == null) {
+                       Log.w("UsbHelper", "no manager");
+                       return null;
+               }
+               HashMap<String,UsbDevice> devlist = manager.getDeviceList();
+               if (devlist == null)
+                       return null;
+               String[] list = devlist.keySet().toArray(new String[devlist.size()]);
+               return list;
+       }
+
        public static int open(String name, int mode)
        {
                try {
@@ -63,5 +105,33 @@ public final class UsbHelper
                        return -1;
                }
        }
+
+       public static void startEventMonitor(UsbEventListener listener)
+       {
+               try {
+                       startEventMonitor(context, manager, listener);
+               } catch (Exception e) {
+                       Log.w("UsbHelper", "caught exception " + e);
+               }
+       }
+
+       public static void stopEventMonitor()
+       {
+               try {
+                       stopEventMonitor(context);
+               } catch (Exception e) {
+                       Log.w("UsbHelper", "caught exception " + e);
+               }
+       }
+
+       public static String[] scanDevices()
+       {
+               try {
+                       return scanDevices(manager);
+               } catch (Exception e) {
+                       Log.w("UsbHelper", "caught exception " + e);
+                       return null;
+               }
+       }
 }
 
index 8a131461eeb5c089aa17d63b81cc2a8c2b45ce06..0f219a87c932c2dbc7466762b1865c0dea00b3da 100644 (file)
@@ -53,7 +53,7 @@ import org.xmlpull.v1.XmlPullParserException;
 
 public class UsbSupplicant
 {
-       private static final String ACTION_USB_PERMISSION =
+       static final String ACTION_USB_PERMISSION =
        "org.sigrok.androidutils.USB_PERMISSION";
 
        protected final Context context;