diff --git a/README.md b/README.md
index d7ce63c..3dd061f 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
UsbSerial
=========
-Usb serial controller for Android. For more information, there is [a more complete description](http://felhr85.net/2014/11/11/usbserial-a-serial-port-driver-library-for-android-v2-0/) and [an example app](https://github.com/felHR85/SerialPortExample).
+Usb serial controller for Android. For more information, there is [a more complete description](http://felhr85.net/2014/11/11/usbserial-a-serial-port-driver-library-for-android-v2-0/).
Devices Supported
--------------------------------------
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 0000000..d115448
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1,3 @@
+/build
+*.jks
+signing.properties
\ No newline at end of file
diff --git a/example/build.gradle b/example/build.gradle
new file mode 100644
index 0000000..b1a4f10
--- /dev/null
+++ b/example/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'com.android.application'
+
+android {
+
+ compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
+ buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
+
+ defaultConfig {
+ applicationId "com.felhr.serialportexample"
+ minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
+ targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
+ versionName project.VERSION_NAME
+ versionCode Integer.parseInt(project.VERSION_CODE)
+ }
+
+ compileOptions {
+ encoding "UTF-8"
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+}
+
+dependencies {
+ compile 'com.android.support:support-v4:23.1.1'
+ compile 'com.android.support:appcompat-v7:23.1.1'
+ compile 'com.android.support:design:23.1.1'
+
+ compile project(':usbserial')
+}
diff --git a/example/proguard-rules.pro b/example/proguard-rules.pro
new file mode 100644
index 0000000..b2fbbf2
--- /dev/null
+++ b/example/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in C:\Program Files (x86)\Android\sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e3ebd4c
--- /dev/null
+++ b/example/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/src/main/java/com/felhr/serialportexample/MainActivity.java b/example/src/main/java/com/felhr/serialportexample/MainActivity.java
new file mode 100644
index 0000000..2a6b9d9
--- /dev/null
+++ b/example/src/main/java/com/felhr/serialportexample/MainActivity.java
@@ -0,0 +1,151 @@
+package com.felhr.serialportexample;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.util.Set;
+
+public class MainActivity extends AppCompatActivity {
+
+ /*
+ * Notifications from UsbService will be received here.
+ */
+ private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case UsbService.ACTION_USB_PERMISSION_GRANTED: // USB PERMISSION GRANTED
+ Toast.makeText(context, "USB Ready", Toast.LENGTH_SHORT).show();
+ break;
+ case UsbService.ACTION_USB_PERMISSION_NOT_GRANTED: // USB PERMISSION NOT GRANTED
+ Toast.makeText(context, "USB Permission not granted", Toast.LENGTH_SHORT).show();
+ break;
+ case UsbService.ACTION_NO_USB: // NO USB CONNECTED
+ Toast.makeText(context, "No USB connected", Toast.LENGTH_SHORT).show();
+ break;
+ case UsbService.ACTION_USB_DISCONNECTED: // USB DISCONNECTED
+ Toast.makeText(context, "USB disconnected", Toast.LENGTH_SHORT).show();
+ break;
+ case UsbService.ACTION_USB_NOT_SUPPORTED: // USB NOT SUPPORTED
+ Toast.makeText(context, "USB device not supported", Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ };
+ private UsbService usbService;
+ private TextView display;
+ private EditText editText;
+ private MyHandler mHandler;
+ private final ServiceConnection usbConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName arg0, IBinder arg1) {
+ usbService = ((UsbService.UsbBinder) arg1).getService();
+ usbService.setHandler(mHandler);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ usbService = null;
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mHandler = new MyHandler(this);
+
+ display = (TextView) findViewById(R.id.textView1);
+ editText = (EditText) findViewById(R.id.editText1);
+ Button sendButton = (Button) findViewById(R.id.buttonSend);
+ sendButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!editText.getText().toString().equals("")) {
+ String data = editText.getText().toString();
+ if (usbService != null) { // if UsbService was correctly binded, Send data
+ display.append(data);
+ usbService.write(data.getBytes());
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ setFilters(); // Start listening notifications from UsbService
+ startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ unregisterReceiver(mUsbReceiver);
+ unbindService(usbConnection);
+ }
+
+ private void startService(Class> service, ServiceConnection serviceConnection, Bundle extras) {
+ if (!UsbService.SERVICE_CONNECTED) {
+ Intent startService = new Intent(this, service);
+ if (extras != null && !extras.isEmpty()) {
+ Set keys = extras.keySet();
+ for (String key : keys) {
+ String extra = extras.getString(key);
+ startService.putExtra(key, extra);
+ }
+ }
+ startService(startService);
+ }
+ Intent bindingIntent = new Intent(this, service);
+ bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void setFilters() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED);
+ filter.addAction(UsbService.ACTION_NO_USB);
+ filter.addAction(UsbService.ACTION_USB_DISCONNECTED);
+ filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED);
+ filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED);
+ registerReceiver(mUsbReceiver, filter);
+ }
+
+ /*
+ * This handler will be passed to UsbService. Data received from serial port is displayed through this handler
+ */
+ private static class MyHandler extends Handler {
+ private final WeakReference mActivity;
+
+ public MyHandler(MainActivity activity) {
+ mActivity = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case UsbService.MESSAGE_FROM_SERIAL_PORT:
+ String data = (String) msg.obj;
+ mActivity.get().display.append(data);
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/java/com/felhr/serialportexample/UsbService.java b/example/src/main/java/com/felhr/serialportexample/UsbService.java
new file mode 100644
index 0000000..49735e3
--- /dev/null
+++ b/example/src/main/java/com/felhr/serialportexample/UsbService.java
@@ -0,0 +1,242 @@
+package com.felhr.serialportexample;
+
+import android.app.PendingIntent;
+import android.app.Service;
+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 android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+
+import com.felhr.usbserial.CDCSerialDevice;
+import com.felhr.usbserial.UsbSerialDevice;
+import com.felhr.usbserial.UsbSerialInterface;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UsbService extends Service {
+
+ public static final String ACTION_USB_READY = "com.felhr.connectivityservices.USB_READY";
+ public static final String ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
+ public static final String ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED";
+ public static final String ACTION_USB_NOT_SUPPORTED = "com.felhr.usbservice.USB_NOT_SUPPORTED";
+ public static final String ACTION_NO_USB = "com.felhr.usbservice.NO_USB";
+ public static final String ACTION_USB_PERMISSION_GRANTED = "com.felhr.usbservice.USB_PERMISSION_GRANTED";
+ public static final String ACTION_USB_PERMISSION_NOT_GRANTED = "com.felhr.usbservice.USB_PERMISSION_NOT_GRANTED";
+ public static final String ACTION_USB_DISCONNECTED = "com.felhr.usbservice.USB_DISCONNECTED";
+ public static final String ACTION_CDC_DRIVER_NOT_WORKING = "com.felhr.connectivityservices.ACTION_CDC_DRIVER_NOT_WORKING";
+ public static final String ACTION_USB_DEVICE_NOT_WORKING = "com.felhr.connectivityservices.ACTION_USB_DEVICE_NOT_WORKING";
+ public static final int MESSAGE_FROM_SERIAL_PORT = 0;
+ private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
+ private static final int BAUD_RATE = 9600; // BaudRate. Change this value if you need
+ public static boolean SERVICE_CONNECTED = false;
+
+ private IBinder binder = new UsbBinder();
+
+ private Context context;
+ private Handler mHandler;
+ private UsbManager usbManager;
+ private UsbDevice device;
+ private UsbDeviceConnection connection;
+ private UsbSerialDevice serialPort;
+
+ private boolean serialPortConnected;
+ /*
+ * Data received from serial port will be received here. Just populate onReceivedData with your code
+ * In this particular example. byte stream is converted to String and send to UI thread to
+ * be treated there.
+ */
+ private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
+ @Override
+ public void onReceivedData(byte[] arg0) {
+ try {
+ String data = new String(arg0, "UTF-8");
+ if (mHandler != null)
+ mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT, data).sendToTarget();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ /*
+ * Different notifications from OS will be received here (USB attached, detached, permission responses...)
+ * About BroadcastReceiver: http://developer.android.com/reference/android/content/BroadcastReceiver.html
+ */
+ private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context arg0, Intent arg1) {
+ if (arg1.getAction().equals(ACTION_USB_PERMISSION)) {
+ boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
+ if (granted) // User accepted our USB connection. Try to open the device as a serial port
+ {
+ Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED);
+ arg0.sendBroadcast(intent);
+ connection = usbManager.openDevice(device);
+ serialPortConnected = true;
+ new ConnectionThread().run();
+ } else // User not accepted our USB connection. Send an Intent to the Main Activity
+ {
+ Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED);
+ arg0.sendBroadcast(intent);
+ }
+ } else if (arg1.getAction().equals(ACTION_USB_ATTACHED)) {
+ if (!serialPortConnected)
+ findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port
+ } else if (arg1.getAction().equals(ACTION_USB_DETACHED)) {
+ // Usb device was disconnected. send an intent to the Main Activity
+ Intent intent = new Intent(ACTION_USB_DISCONNECTED);
+ arg0.sendBroadcast(intent);
+ serialPortConnected = false;
+ serialPort.close();
+ }
+ }
+ };
+
+ /*
+ * onCreate will be executed when service is started. It configures an IntentFilter to listen for
+ * incoming Intents (USB ATTACHED, USB DETACHED...) and it tries to open a serial port.
+ */
+ @Override
+ public void onCreate() {
+ this.context = this;
+ serialPortConnected = false;
+ UsbService.SERVICE_CONNECTED = true;
+ setFilter();
+ usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+ findSerialPortDevice();
+ }
+
+ /* MUST READ about services
+ * http://developer.android.com/guide/components/services.html
+ * http://developer.android.com/guide/components/bound-services.html
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return binder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ UsbService.SERVICE_CONNECTED = false;
+ }
+
+ /*
+ * This function will be called from MainActivity to write data through Serial Port
+ */
+ public void write(byte[] data) {
+ if (serialPort != null)
+ serialPort.write(data);
+ }
+
+ public void setHandler(Handler mHandler) {
+ this.mHandler = mHandler;
+ }
+
+ private void findSerialPortDevice() {
+ // This snippet will try to open the first encountered usb device connected, excluding usb root hubs
+ HashMap usbDevices = usbManager.getDeviceList();
+ if (!usbDevices.isEmpty()) {
+ boolean keep = true;
+ for (Map.Entry entry : usbDevices.entrySet()) {
+ device = entry.getValue();
+ int deviceVID = device.getVendorId();
+ int devicePID = device.getProductId();
+
+ if (deviceVID != 0x1d6b && (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003)) {
+ // There is a device connected to our Android device. Try to open it as a Serial Port.
+ requestUserPermission();
+ keep = false;
+ } else {
+ connection = null;
+ device = null;
+ }
+
+ if (!keep)
+ break;
+ }
+ if (!keep) {
+ // There is no USB devices connected (but usb host were listed). Send an intent to MainActivity.
+ Intent intent = new Intent(ACTION_NO_USB);
+ sendBroadcast(intent);
+ }
+ } else {
+ // There is no USB devices connected. Send an intent to MainActivity
+ Intent intent = new Intent(ACTION_NO_USB);
+ sendBroadcast(intent);
+ }
+ }
+
+ private void setFilter() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USB_PERMISSION);
+ filter.addAction(ACTION_USB_DETACHED);
+ filter.addAction(ACTION_USB_ATTACHED);
+ registerReceiver(usbReceiver, filter);
+ }
+
+ /*
+ * Request user permission. The response will be received in the BroadcastReceiver
+ */
+ private void requestUserPermission() {
+ PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+ usbManager.requestPermission(device, mPendingIntent);
+ }
+
+ public class UsbBinder extends Binder {
+ public UsbService getService() {
+ return UsbService.this;
+ }
+ }
+
+ /*
+ * A simple thread to open a serial port.
+ * Although it should be a fast operation. moving usb operations away from UI thread is a good thing.
+ */
+ private class ConnectionThread extends Thread {
+ @Override
+ public void run() {
+ serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
+ if (serialPort != null) {
+ if (serialPort.open()) {
+ serialPort.setBaudRate(BAUD_RATE);
+ serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
+ serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
+ serialPort.setParity(UsbSerialInterface.PARITY_NONE);
+ serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
+ serialPort.read(mCallback);
+
+ // Everything went as expected. Send an intent to MainActivity
+ Intent intent = new Intent(ACTION_USB_READY);
+ context.sendBroadcast(intent);
+ } else {
+ // Serial port could not be opened, maybe an I/O error or if CDC driver was chosen, it does not really fit
+ // Send an Intent to Main Activity
+ if (serialPort instanceof CDCSerialDevice) {
+ Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING);
+ context.sendBroadcast(intent);
+ } else {
+ Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING);
+ context.sendBroadcast(intent);
+ }
+ }
+ } else {
+ // No driver for given device, even generic CDC driver could not be loaded
+ Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED);
+ context.sendBroadcast(intent);
+ }
+ }
+ }
+}
diff --git a/example/src/main/res/com/felhr/serialportexample/MainActivity.java b/example/src/main/res/com/felhr/serialportexample/MainActivity.java
new file mode 100644
index 0000000..2f966ca
--- /dev/null
+++ b/example/src/main/res/com/felhr/serialportexample/MainActivity.java
@@ -0,0 +1,199 @@
+package com.felhr.serialportexample;
+
+import java.lang.ref.WeakReference;
+import java.util.Set;
+
+import android.support.v7.app.ActionBarActivity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+public class MainActivity extends ActionBarActivity implements View.OnClickListener
+{
+ private UsbService usbService;
+
+ private TextView display;
+ private EditText editText;
+ private Button sendButton;
+
+ private MyHandler mHandler;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mHandler = new MyHandler(this);
+
+ display = (TextView) findViewById(R.id.textView1);
+ editText = (EditText) findViewById(R.id.editText1);
+ sendButton = (Button) findViewById(R.id.buttonSend);
+ sendButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ setFilters(); // Start listening notifications from UsbService
+ startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ unregisterReceiver(mUsbReceiver);
+ unbindService(usbConnection);
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+ if (id == R.id.action_settings)
+ {
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+
+ @Override
+ public void onClick(View v)
+ {
+ if(!editText.getText().toString().equals(""))
+ {
+ String data = editText.getText().toString();
+ if(usbService != null) // if UsbService was correctly binded, Send data
+ usbService.write(data.getBytes());
+ }
+ }
+
+ private void startService(Class> service, ServiceConnection serviceConnection, Bundle extras)
+ {
+ if(UsbService.SERVICE_CONNECTED == false)
+ {
+ Intent startService = new Intent(this, service);
+ if(extras != null && !extras.isEmpty())
+ {
+ Set keys = extras.keySet();
+ for(String key: keys)
+ {
+ String extra = extras.getString(key);
+ startService.putExtra(key, extra);
+ }
+ }
+ startService(startService);
+ }
+ Intent bindingIntent = new Intent(this, service);
+ bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void setFilters()
+ {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED);
+ filter.addAction(UsbService.ACTION_NO_USB);
+ filter.addAction(UsbService.ACTION_USB_DISCONNECTED);
+ filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED);
+ filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED);
+ registerReceiver(mUsbReceiver, filter);
+ }
+
+ /*
+ * This handler will be passed to UsbService. Dara received from serial port is displayed through this handler
+ */
+ private static class MyHandler extends Handler
+ {
+ private final WeakReference mActivity;
+
+ public MyHandler(MainActivity activity)
+ {
+ mActivity = new WeakReference(activity);
+ }
+
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch(msg.what)
+ {
+ case UsbService.MESSAGE_FROM_SERIAL_PORT:
+ String data = (String) msg.obj;
+ mActivity.get().display.append(data);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Notifications from UsbService will be received here.
+ */
+ private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver()
+ {
+ @Override
+ public void onReceive(Context arg0, Intent arg1)
+ {
+ if(arg1.getAction().equals(UsbService.ACTION_USB_PERMISSION_GRANTED)) // USB PERMISSION GRANTED
+ {
+ Toast.makeText(arg0, "USB Ready", Toast.LENGTH_SHORT).show();
+ }else if(arg1.getAction().equals(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED)) // USB PERMISSION NOT GRANTED
+ {
+ Toast.makeText(arg0, "USB Permission not granted", Toast.LENGTH_SHORT).show();
+ }else if(arg1.getAction().equals(UsbService.ACTION_NO_USB)) // NO USB CONNECTED
+ {
+ Toast.makeText(arg0, "No USB connected", Toast.LENGTH_SHORT).show();
+ }else if(arg1.getAction().equals(UsbService.ACTION_USB_DISCONNECTED)) // USB DISCONNECTED
+ {
+ Toast.makeText(arg0, "USB disconnected", Toast.LENGTH_SHORT).show();
+ }else if(arg1.getAction().equals(UsbService.ACTION_USB_NOT_SUPPORTED)) // USB NOT SUPPORTED
+ {
+ Toast.makeText(arg0, "USB device not supported", Toast.LENGTH_SHORT).show();
+ }
+ }
+ };
+
+ private final ServiceConnection usbConnection = new ServiceConnection()
+ {
+ @Override
+ public void onServiceConnected(ComponentName arg0, IBinder arg1)
+ {
+ usbService = ((UsbService.UsbBinder) arg1).getService();
+ usbService.setHandler(mHandler);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0)
+ {
+ usbService = null;
+ }
+ };
+}
\ No newline at end of file
diff --git a/example/src/main/res/com/felhr/serialportexample/UsbService.java b/example/src/main/res/com/felhr/serialportexample/UsbService.java
new file mode 100644
index 0000000..1420ac0
--- /dev/null
+++ b/example/src/main/res/com/felhr/serialportexample/UsbService.java
@@ -0,0 +1,283 @@
+package com.felhr.serialportexample;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.felhr.usbserial.CDCSerialDevice;
+import com.felhr.usbserial.UsbSerialDevice;
+import com.felhr.usbserial.UsbSerialInterface;
+
+import android.app.PendingIntent;
+import android.app.Service;
+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 android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+public class UsbService extends Service
+{
+ public static final String ACTION_USB_READY = "com.felhr.connectivityservices.USB_READY";
+ private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
+ public static final String ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
+ public static final String ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED";
+ public static final String ACTION_USB_NOT_SUPPORTED = "com.felhr.usbservice.USB_NOT_SUPPORTED";
+ public static final String ACTION_NO_USB = "com.felhr.usbservice.NO_USB";
+ public static final String ACTION_USB_PERMISSION_GRANTED = "com.felhr.usbservice.USB_PERMISSION_GRANTED";
+ public static final String ACTION_USB_PERMISSION_NOT_GRANTED = "com.felhr.usbservice.USB_PERMISSION_NOT_GRANTED";
+ public static final String ACTION_USB_DISCONNECTED = "com.felhr.usbservice.USB_DISCONNECTED";
+ public static final String ACTION_CDC_DRIVER_NOT_WORKING ="com.felhr.connectivityservices.ACTION_CDC_DRIVER_NOT_WORKING";
+ public static final String ACTION_USB_DEVICE_NOT_WORKING = "com.felhr.connectivityservices.ACTION_USB_DEVICE_NOT_WORKING";
+
+ private static final int BAUD_RATE = 9600; // BaudRate. Change this value if you need
+ public static final int MESSAGE_FROM_SERIAL_PORT = 0;
+
+ public static boolean SERVICE_CONNECTED = false;
+
+ private IBinder binder = new UsbBinder();
+
+ private Context context;
+ private Handler mHandler;
+ private UsbManager usbManager;
+ private UsbDevice device;
+ private UsbDeviceConnection connection;
+ private UsbSerialDevice serialPort;
+
+ private boolean serialPortConnected;
+
+ /*
+ * onCreate will be executed when service is started. It configures an IntentFilter to listen for
+ * incoming Intents (USB ATTACHED, USB DETACHED...) and it tries to open a serial port.
+ */
+ @Override
+ public void onCreate()
+ {
+ this.context = this;
+ serialPortConnected = false;
+ UsbService.SERVICE_CONNECTED = true;
+ setFilter();
+ usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+ findSerialPortDevice();
+ }
+
+ /* MUST READ about services
+ * http://developer.android.com/guide/components/services.html
+ * http://developer.android.com/guide/components/bound-services.html
+ */
+ @Override
+ public IBinder onBind(Intent intent)
+ {
+ return binder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId)
+ {
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ UsbService.SERVICE_CONNECTED = false;
+ }
+
+ /*
+ * This function will be called from MainActivity to write data through Serial Port
+ */
+ public void write(byte[] data)
+ {
+ if(serialPort != null)
+ serialPort.write(data);
+ }
+
+ public void setHandler(Handler mHandler)
+ {
+ this.mHandler = mHandler;
+ }
+
+ private void findSerialPortDevice()
+ {
+ // This snippet will try to open the first encountered usb device connected, excluding usb root hubs
+ HashMap usbDevices = usbManager.getDeviceList();
+ if(!usbDevices.isEmpty())
+ {
+ boolean keep = true;
+ for(Map.Entry entry : usbDevices.entrySet())
+ {
+ device = entry.getValue();
+ int deviceVID = device.getVendorId();
+ int devicePID = device.getProductId();
+
+ if(deviceVID != 0x1d6b && (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003))
+ {
+ // There is a device connected to our Android device. Try to open it as a Serial Port.
+ requestUserPermission();
+ keep = false;
+ }else
+ {
+ connection = null;
+ device = null;
+ }
+
+ if(!keep)
+ break;
+ }
+ if(!keep)
+ {
+ // There is no USB devices connected (but usb host were listed). Send an intent to MainActivity.
+ Intent intent = new Intent(ACTION_NO_USB);
+ sendBroadcast(intent);
+ }
+ }else
+ {
+ // There is no USB devices connected. Send an intent to MainActivity
+ Intent intent = new Intent(ACTION_NO_USB);
+ sendBroadcast(intent);
+ }
+ }
+
+ private void setFilter()
+ {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USB_PERMISSION);
+ filter.addAction(ACTION_USB_DETACHED);
+ filter.addAction(ACTION_USB_ATTACHED);
+ registerReceiver(usbReceiver , filter);
+ }
+
+ /*
+ * Request user permission. The response will be received in the BroadcastReceiver
+ */
+ private void requestUserPermission()
+ {
+ PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION),0);
+ usbManager.requestPermission(device, mPendingIntent);
+ }
+
+ /*
+ * Data received from serial port will be received here. Just populate onReceivedData with your code
+ * In this particular example. byte stream is converted to String and send to UI thread to
+ * be treated there.
+ */
+ private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback()
+ {
+ @Override
+ public void onReceivedData(byte[] arg0)
+ {
+ try
+ {
+ String data = new String(arg0, "UTF-8");
+ if(mHandler != null)
+ mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT,data).sendToTarget();
+ } catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ public class UsbBinder extends Binder
+ {
+ public UsbService getService()
+ {
+ return UsbService.this;
+ }
+ }
+
+ /*
+ * Different notifications from OS will be received here (USB attached, detached, permission responses...)
+ * About BroadcastReceiver: http://developer.android.com/reference/android/content/BroadcastReceiver.html
+ */
+ private final BroadcastReceiver usbReceiver = new BroadcastReceiver()
+ {
+ @Override
+ public void onReceive(Context arg0, Intent arg1)
+ {
+ if(arg1.getAction().equals(ACTION_USB_PERMISSION))
+ {
+ boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
+ if(granted) // User accepted our USB connection. Try to open the device as a serial port
+ {
+ Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED);
+ arg0.sendBroadcast(intent);
+ connection = usbManager.openDevice(device);
+ serialPortConnected = true;
+ new ConnectionThread().run();
+ }else // User not accepted our USB connection. Send an Intent to the Main Activity
+ {
+ Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED);
+ arg0.sendBroadcast(intent);
+ }
+ }else if(arg1.getAction().equals(ACTION_USB_ATTACHED))
+ {
+ if(!serialPortConnected)
+ findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port
+ }else if(arg1.getAction().equals(ACTION_USB_DETACHED))
+ {
+ // Usb device was disconnected. send an intent to the Main Activity
+ Intent intent = new Intent(ACTION_USB_DISCONNECTED);
+ arg0.sendBroadcast(intent);
+ serialPortConnected = false;
+ serialPort.close();
+ }
+ }
+ };
+
+ /*
+ * A simple thread to open a serial port.
+ * Although it should be a fast operation. moving usb operations away from UI thread is a good thing.
+ */
+ private class ConnectionThread extends Thread
+ {
+ @Override
+ public void run()
+ {
+ serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
+ if(serialPort != null)
+ {
+ if(serialPort.open())
+ {
+ serialPort.setBaudRate(BAUD_RATE);
+ serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
+ serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
+ serialPort.setParity(UsbSerialInterface.PARITY_NONE);
+ serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
+ serialPort.read(mCallback);
+
+ // Everything went as expected. Send an intent to MainActivity
+ Intent intent = new Intent(ACTION_USB_READY);
+ context.sendBroadcast(intent);
+ }else
+ {
+ // Serial port could not be opened, maybe an I/O error or if CDC driver was chosen, it does not really fit
+ // Send an Intent to Main Activity
+ if(serialPort instanceof CDCSerialDevice)
+ {
+ Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING);
+ context.sendBroadcast(intent);
+ }else
+ {
+ Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING);
+ context.sendBroadcast(intent);
+ }
+ }
+ }else
+ {
+ // No driver for given device, even generic CDC driver could not be loaded
+ Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED);
+ context.sendBroadcast(intent);
+ }
+ }
+ }
+
+}
diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..07d57c6
--- /dev/null
+++ b/example/src/main/res/layout/activity_main.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d9cad20
Binary files /dev/null and b/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/example/src/main/res/values-w820dp/dimens.xml b/example/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..f3e7020
--- /dev/null
+++ b/example/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,10 @@
+
+
+
+ 64dp
+
+
diff --git a/example/src/main/res/values/dimens.xml b/example/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..55c1e59
--- /dev/null
+++ b/example/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+
+ 16dp
+ 16dp
+
+
diff --git a/example/src/main/res/values/strings.xml b/example/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c24a5f0
--- /dev/null
+++ b/example/src/main/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+
+
+ SerialPortExample
+ Hello world!
+ Settings
+ Serial Port
+
+
diff --git a/example/src/main/res/values/styles.xml b/example/src/main/res/values/styles.xml
new file mode 100644
index 0000000..845fb57
--- /dev/null
+++ b/example/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
diff --git a/gradle.properties b/gradle.properties
index ae6f161..7837fbb 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,6 @@
+VERSION_NAME=1.0
+VERSION_CODE=1
+
ANDROID_BUILD_MIN_SDK_VERSION=12
ANDROID_BUILD_TARGET_SDK_VERSION=23
ANDROID_BUILD_SDK_VERSION=23
diff --git a/settings.gradle b/settings.gradle
index 82ec713..3613446 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':usbserial'
\ No newline at end of file
+include ':usbserial', ':example'
\ No newline at end of file
diff --git a/usbserial/build.gradle b/usbserial/build.gradle
index 18f2070..f37e32a 100644
--- a/usbserial/build.gradle
+++ b/usbserial/build.gradle
@@ -18,7 +18,4 @@ android {
minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
}
-
- dependencies {
- }
}