From 6e095fe0b74ee090603fc25980fa0c71f61c6467 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Sun, 24 Dec 2017 16:44:46 +0200 Subject: Implemented UsbSerialAdapter for android. --- .../java/com/twine/tango/core/ContextHelper.java | 24 +++ .../Tango.Stubs.UI/src/main/AndroidManifest.xml | 8 + .../tango/stubs/ui/dagger/IntegrationModule.java | 4 +- .../tango/stubs/ui/views/main/MainActivity.java | 4 + .../Android_Studio/Tango.Transport/build.gradle | 1 + .../Tango.Transport/src/main/AndroidManifest.xml | 4 +- .../transport/adapters/UsbTransportAdapter.java | 173 ++++++++++++++++++++- Software/Android_Studio/build.gradle | 3 +- 8 files changed, 217 insertions(+), 4 deletions(-) (limited to 'Software/Android_Studio') diff --git a/Software/Android_Studio/Tango.Core/src/main/java/com/twine/tango/core/ContextHelper.java b/Software/Android_Studio/Tango.Core/src/main/java/com/twine/tango/core/ContextHelper.java index 768376d9d..59151f896 100644 --- a/Software/Android_Studio/Tango.Core/src/main/java/com/twine/tango/core/ContextHelper.java +++ b/Software/Android_Studio/Tango.Core/src/main/java/com/twine/tango/core/ContextHelper.java @@ -1,6 +1,7 @@ package com.twine.tango.core; import android.content.Context; +import android.support.v7.app.AppCompatActivity; /** @@ -9,6 +10,7 @@ import android.content.Context; public class ContextHelper { private static Context appContext; + private static AppCompatActivity mainActivity; /** * Initializes the helper with the application context. @@ -21,6 +23,17 @@ public class ContextHelper appContext = context; } + + /** + * Register the application main activity. + * + * @param activity the activity + */ + public static void registerMainActivity(AppCompatActivity activity) + { + mainActivity = activity; + } + /** * Gets the application context. * @@ -30,4 +43,15 @@ public class ContextHelper { return appContext; } + + + /** + * Gets the application main activity. + * + * @return the main activity + */ + public static AppCompatActivity getMainActivity() + { + return mainActivity; + } } diff --git a/Software/Android_Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml b/Software/Android_Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml index e699ecbd3..ad99a3b57 100644 --- a/Software/Android_Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml +++ b/Software/Android_Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.twine.tango.stubs.ui"> + + + + + + diff --git a/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java b/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java index b06d9aa67..7fd86f537 100644 --- a/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java +++ b/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java @@ -9,6 +9,7 @@ import com.twine.tango.integration.services.ISynchronizationService; import com.twine.tango.integration.services.ExternalBridgeService; import com.twine.tango.integration.services.SynchronizationService; import com.twine.tango.transport.adapters.TcpTransportAdapter; +import com.twine.tango.transport.adapters.UsbTransportAdapter; import javax.inject.Singleton; import dagger.Module; @@ -45,6 +46,7 @@ public class IntegrationModule @Singleton public IMachineOperator providerMachineOperator() { - return new MachineOperator(new TcpTransportAdapter("10.0.2.2", 9999)); + //return new MachineOperator(new TcpTransportAdapter("10.0.2.2", 9999)); + return new MachineOperator(new UsbTransportAdapter()); } } diff --git a/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/main/MainActivity.java b/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/main/MainActivity.java index c2699c640..c1f85b971 100644 --- a/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/main/MainActivity.java +++ b/Software/Android_Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/main/MainActivity.java @@ -6,6 +6,8 @@ import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.view.View; + +import com.twine.tango.core.ContextHelper; import com.twine.tango.sharedui.containers.ActivityBase; import com.twine.tango.sharedui.navigation.INavigationProvider; import com.twine.tango.stubs.ui.App; @@ -26,6 +28,8 @@ public class MainActivity extends ActivityBase + package="com.twine.tango.transport"> + + diff --git a/Software/Android_Studio/Tango.Transport/src/main/java/com/twine/tango/transport/adapters/UsbTransportAdapter.java b/Software/Android_Studio/Tango.Transport/src/main/java/com/twine/tango/transport/adapters/UsbTransportAdapter.java index 3699ebc76..8ad55708c 100644 --- a/Software/Android_Studio/Tango.Transport/src/main/java/com/twine/tango/transport/adapters/UsbTransportAdapter.java +++ b/Software/Android_Studio/Tango.Transport/src/main/java/com/twine/tango/transport/adapters/UsbTransportAdapter.java @@ -1,9 +1,180 @@ package com.twine.tango.transport.adapters; +import android.app.PendingIntent; +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.UsbDeviceConnection; +import android.hardware.usb.UsbManager; + +import com.elvishew.xlog.XLog; +import com.felhr.usbserial.UsbSerialDevice; +import com.felhr.usbserial.UsbSerialInterface; +import com.twine.tango.core.ContextHelper; +import com.twine.tango.core.ObjectDisposedException; +import com.twine.tango.transport.TransportAdapterBase; +import com.twine.tango.transport.TransportComponentState; + +import java.io.IOException; +import java.util.Map; + +import io.reactivex.Completable; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; + /** * Created by Roy on 12/24/2017. */ -public class UsbTransportAdapter +public class UsbTransportAdapter extends TransportAdapterBase { + private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; + + private UsbSerialDevice serial; + private PendingIntent mPermissionIntent; + private UsbManager usbManager; + private boolean hasPermission; + private PublishSubject connectionSubject; + + public UsbTransportAdapter() + { + setAddress("0x1CBE"); + } + + public UsbTransportAdapter(String address) + { + setAddress(address); + } + + @Override + public void write(byte[] data) throws ObjectDisposedException, IOException + { + serial.write(data); + } + + @Override + public Completable connect() + { + connectionSubject = PublishSubject.create(); + + try + { + if (!hasPermission) + { + mPermissionIntent = PendingIntent.getBroadcast(ContextHelper.getMainActivity(), 0, new Intent(ACTION_USB_PERMISSION), 0); + IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); + ContextHelper.getMainActivity().registerReceiver(mUsbReceiver, filter); + } + + usbManager = (UsbManager) ContextHelper.getMainActivity().getSystemService(Context.USB_SERVICE); + Map connectedDevices = usbManager.getDeviceList(); + + for (UsbDevice device : connectedDevices.values()) + { + if (device.getVendorId() == Integer.decode(getAddress())) + { + XLog.i("USB Device found: " + device.getManufacturerName()); + usbManager.requestPermission(device, mPermissionIntent); + break; + } + } + } catch (Exception ex) + { + notifyConnectionFailed(ex); + } + + return connectionSubject.subscribeOn(Schedulers.io()).singleOrError().toCompletable(); + } + + private void notifyConnectionSuccess() + { + setState(TransportComponentState.Connected); + //noinspection unchecked + connectionSubject.onNext(new Object()); + connectionSubject.onComplete(); + } + + private void notifyConnectionFailed(Exception ex) + { + connectionSubject.onError(ex); + } + + private void initConnection(UsbDevice device) + { + try + { + UsbDeviceConnection connection = usbManager.openDevice(device); + serial = UsbSerialDevice.createUsbSerialDevice(device, connection); + + if (serial != null && serial.open()) + { + serial.setBaudRate(9600); + serial.setDataBits(UsbSerialInterface.DATA_BITS_8); + serial.setStopBits(UsbSerialInterface.STOP_BITS_1); + serial.setParity(UsbSerialInterface.PARITY_NONE); + serial.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF); + serial.read(this::onUsbReceiveData); + notifyConnectionSuccess(); + } + } catch (Exception ex) + { + notifyConnectionFailed(ex); + } + } + + private void onUsbReceiveData(byte[] data) + { + onDataAvailable(data); + } + + @Override + public Completable disconnect() + { + return Completable.create((x) -> + { + try + { + if (serial != null) + { + serial.close(); + setState(TransportComponentState.Disconnected); + x.onComplete(); + } + } catch (Exception ex) + { + x.onError(ex); + } + + }).subscribeOn(Schedulers.io()); + } + + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() + { + + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (ACTION_USB_PERMISSION.equals(action)) + { + synchronized (this) + { + UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) + { + if (device != null) + { + hasPermission = true; + initConnection(device); + } + } else + { + notifyConnectionFailed(new IllegalAccessException("Permission denied for device " + device.getDeviceName())); + } + } + } + } + }; } diff --git a/Software/Android_Studio/build.gradle b/Software/Android_Studio/build.gradle index 73b52173e..3152cdfc2 100644 --- a/Software/Android_Studio/build.gradle +++ b/Software/Android_Studio/build.gradle @@ -42,7 +42,8 @@ ext { storage: 'com.snatik:storage:2.1.0', retrofit: 'com.squareup.retrofit2:retrofit:2.3.0', retrofit_protobuf: 'com.squareup.retrofit2:converter-protobuf:2.3.0', - retrofit_rxJava: 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' + retrofit_rxJava: 'com.squareup.retrofit2:adapter-rxjava2:2.3.0', + usb: 'com.github.felHR85:UsbSerial:4.5' ] } -- cgit v1.3.1