modernize example app
|
@ -39,7 +39,7 @@
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
@ -96,12 +96,12 @@ and finally:
|
||||||
port.close();
|
port.close();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
For a simple example, see
|
For a simple example, see
|
||||||
[UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
|
[UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
|
||||||
folder in this project.
|
folder in this project.
|
||||||
|
|
||||||
For a more complete example, see separate github project
|
For a more complete example with background service to stay connected while
|
||||||
|
the app is not visible or rotating, see separate github project
|
||||||
[SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal).
|
[SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal).
|
||||||
|
|
||||||
## Probing for Unrecognized Devices
|
## Probing for Unrecognized Devices
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#android.enableJetifier=true
|
||||||
|
android.useAndroidX=true
|
|
@ -4,6 +4,11 @@ android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '28.0.3'
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 17
|
minSdkVersion 17
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
|
@ -21,4 +26,6 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':usbSerialForAndroid')
|
implementation project(':usbSerialForAndroid')
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,33 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.hoho.android.usbserial.examples"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:versionCode="1"
|
package="com.hoho.android.usbserial.examples">
|
||||||
android:versionName="1.0" >
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.usb.host" />
|
|
||||||
|
|
||||||
|
<!-- mipmap/ic_launcher created with Android Studio -> New -> Image Asset using @color/colorPrimary and USB clip art -->
|
||||||
<application
|
<application
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name" >
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||||
|
<!-- for this simple app launchMode=singleTask and singleTop have same effect.
|
||||||
|
If you would start another activity in the app, e.g. Android Settings
|
||||||
|
then you should use singleTask, else a new MainActivity would be started
|
||||||
|
when the settings activity is currently shown -->
|
||||||
<activity
|
<activity
|
||||||
android:name="com.hoho.android.usbserial.examples.DeviceListActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
|
android:launchMode="singleTask"
|
||||||
|
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
android:resource="@xml/device_filter" />
|
android:resource="@xml/device_filter" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
android:name="com.hoho.android.usbserial.examples.SerialConsoleActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
|
|
||||||
</activity>
|
|
||||||
</application>
|
</application>
|
||||||
|
</manifest>
|
||||||
</manifest>
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.hoho.android.usbserial.examples;
|
||||||
|
|
||||||
|
import com.hoho.android.usbserial.driver.CdcAcmSerialDriver;
|
||||||
|
import com.hoho.android.usbserial.driver.ProbeTable;
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add devices here, that are not known to DefaultProber
|
||||||
|
*
|
||||||
|
* if the App should auto start for these devices, also
|
||||||
|
* add IDs to app/src/main/res/xml/device_filter.xml
|
||||||
|
*/
|
||||||
|
class CustomProber {
|
||||||
|
|
||||||
|
static UsbSerialProber getCustomProber() {
|
||||||
|
ProbeTable customTable = new ProbeTable();
|
||||||
|
customTable.addProduct(0x16d0, 0x087e, CdcAcmSerialDriver.class); // e.g. Digispark CDC
|
||||||
|
return new UsbSerialProber(customTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,233 +0,0 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
||||||
* USA.
|
|
||||||
*
|
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.hoho.android.usbserial.examples;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
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.UsbManager;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import android.widget.TwoLineListItem;
|
|
||||||
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a {@link ListView} of available USB devices.
|
|
||||||
*
|
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
|
||||||
*/
|
|
||||||
public class DeviceListActivity extends Activity {
|
|
||||||
|
|
||||||
private final String TAG = DeviceListActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
private UsbManager mUsbManager;
|
|
||||||
private UsbSerialPort mSerialPort;
|
|
||||||
private ListView mListView;
|
|
||||||
private TextView mProgressBarTitle;
|
|
||||||
private ProgressBar mProgressBar;
|
|
||||||
|
|
||||||
private static final int MESSAGE_REFRESH = 101;
|
|
||||||
private static final long REFRESH_TIMEOUT_MILLIS = 5000;
|
|
||||||
public static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
|
|
||||||
|
|
||||||
private final Handler mHandler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MESSAGE_REFRESH:
|
|
||||||
refreshDeviceList();
|
|
||||||
mHandler.sendEmptyMessageDelayed(MESSAGE_REFRESH, REFRESH_TIMEOUT_MILLIS);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
super.handleMessage(msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
private BroadcastReceiver mUsbReceiver;
|
|
||||||
|
|
||||||
private List<UsbSerialPort> mEntries = new ArrayList<UsbSerialPort>();
|
|
||||||
private ArrayAdapter<UsbSerialPort> mAdapter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.main);
|
|
||||||
final Context context = this;
|
|
||||||
|
|
||||||
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
|
||||||
mListView = findViewById(R.id.deviceList);
|
|
||||||
mProgressBar = findViewById(R.id.progressBar);
|
|
||||||
mProgressBarTitle = findViewById(R.id.progressBarTitle);
|
|
||||||
|
|
||||||
mUsbReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if(intent.getAction().equals(INTENT_ACTION_GRANT_USB)) {
|
|
||||||
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
|
|
||||||
showConsoleActivity(mSerialPort);
|
|
||||||
} else {
|
|
||||||
Toast.makeText(context, "USB permission denied", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mAdapter = new ArrayAdapter<UsbSerialPort>(this,
|
|
||||||
android.R.layout.simple_expandable_list_item_2, mEntries) {
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
|
||||||
final TwoLineListItem row;
|
|
||||||
if (convertView == null){
|
|
||||||
final LayoutInflater inflater =
|
|
||||||
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
row = (TwoLineListItem) inflater.inflate(android.R.layout.simple_list_item_2, null);
|
|
||||||
} else {
|
|
||||||
row = (TwoLineListItem) convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
final UsbSerialPort port = mEntries.get(position);
|
|
||||||
final UsbSerialDriver driver = port.getDriver();
|
|
||||||
final UsbDevice device = driver.getDevice();
|
|
||||||
|
|
||||||
final String title = String.format("Vendor %4X Product %4X", device.getVendorId(), device.getProductId());
|
|
||||||
row.getText1().setText(title);
|
|
||||||
|
|
||||||
final String subtitle = driver.getClass().getSimpleName();
|
|
||||||
row.getText2().setText(subtitle);
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
mListView.setAdapter(mAdapter);
|
|
||||||
|
|
||||||
mListView.setOnItemClickListener(new ListView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
Log.d(TAG, "Pressed item " + position);
|
|
||||||
if (position >= mEntries.size()) {
|
|
||||||
Log.w(TAG, "Illegal position.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSerialPort = mEntries.get(position);
|
|
||||||
UsbDevice device = mSerialPort.getDriver().getDevice();
|
|
||||||
if (!mUsbManager.hasPermission(device)) {
|
|
||||||
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
|
|
||||||
mUsbManager.requestPermission(device, usbPermissionIntent);
|
|
||||||
} else {
|
|
||||||
showConsoleActivity(mSerialPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
mHandler.sendEmptyMessage(MESSAGE_REFRESH);
|
|
||||||
registerReceiver(mUsbReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mHandler.removeMessages(MESSAGE_REFRESH);
|
|
||||||
unregisterReceiver(mUsbReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshDeviceList() {
|
|
||||||
showProgressBar();
|
|
||||||
|
|
||||||
new AsyncTask<Void, Void, List<UsbSerialPort>>() {
|
|
||||||
@Override
|
|
||||||
protected List<UsbSerialPort> doInBackground(Void... params) {
|
|
||||||
Log.d(TAG, "Refreshing device list ...");
|
|
||||||
SystemClock.sleep(1000);
|
|
||||||
|
|
||||||
final List<UsbSerialDriver> drivers =
|
|
||||||
UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);
|
|
||||||
|
|
||||||
final List<UsbSerialPort> result = new ArrayList<UsbSerialPort>();
|
|
||||||
for (final UsbSerialDriver driver : drivers) {
|
|
||||||
final List<UsbSerialPort> ports = driver.getPorts();
|
|
||||||
Log.d(TAG, String.format("+ %s: %s port%s",
|
|
||||||
driver, Integer.valueOf(ports.size()), ports.size() == 1 ? "" : "s"));
|
|
||||||
result.addAll(ports);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(List<UsbSerialPort> result) {
|
|
||||||
mEntries.clear();
|
|
||||||
mEntries.addAll(result);
|
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
mProgressBarTitle.setText(
|
|
||||||
String.format("%s device(s) found",Integer.valueOf(mEntries.size())));
|
|
||||||
hideProgressBar();
|
|
||||||
Log.d(TAG, "Done refreshing, " + mEntries.size() + " entries found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}.execute((Void) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showProgressBar() {
|
|
||||||
mProgressBar.setVisibility(View.VISIBLE);
|
|
||||||
mProgressBarTitle.setText(R.string.refreshing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideProgressBar() {
|
|
||||||
mProgressBar.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showConsoleActivity(UsbSerialPort port) {
|
|
||||||
SerialConsoleActivity.show(this, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
package com.hoho.android.usbserial.examples;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.ListFragment;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class DevicesFragment extends ListFragment {
|
||||||
|
|
||||||
|
class ListItem {
|
||||||
|
UsbDevice device;
|
||||||
|
int port;
|
||||||
|
UsbSerialDriver driver;
|
||||||
|
|
||||||
|
ListItem(UsbDevice device, int port, UsbSerialDriver driver) {
|
||||||
|
this.device = device;
|
||||||
|
this.port = port;
|
||||||
|
this.driver = driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<ListItem> listItems = new ArrayList<>();
|
||||||
|
private ArrayAdapter<ListItem> listAdapter;
|
||||||
|
private int baudRate = 19200;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
listAdapter = new ArrayAdapter<ListItem>(getActivity(), 0, listItems) {
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View view, ViewGroup parent) {
|
||||||
|
ListItem item = listItems.get(position);
|
||||||
|
if (view == null)
|
||||||
|
view = getActivity().getLayoutInflater().inflate(R.layout.device_list_item, parent, false);
|
||||||
|
TextView text1 = view.findViewById(R.id.text1);
|
||||||
|
TextView text2 = view.findViewById(R.id.text2);
|
||||||
|
if(item.driver == null)
|
||||||
|
text1.setText("<no driver>");
|
||||||
|
else if(item.driver.getPorts().size() == 1)
|
||||||
|
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver",""));
|
||||||
|
else
|
||||||
|
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver","")+", Port "+item.port);
|
||||||
|
text2.setText(String.format(Locale.US, "Vendor %04X, Product %04X", item.device.getVendorId(), item.device.getProductId()));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
setListAdapter(null);
|
||||||
|
View header = getActivity().getLayoutInflater().inflate(R.layout.device_list_header, null, false);
|
||||||
|
getListView().addHeaderView(header, null, false);
|
||||||
|
setEmptyText("<no USB devices found>");
|
||||||
|
((TextView) getListView().getEmptyView()).setTextSize(18);
|
||||||
|
setListAdapter(listAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.menu_devices, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if(id == R.id.refresh) {
|
||||||
|
refresh();
|
||||||
|
return true;
|
||||||
|
} else if (id ==R.id.baud_rate) {
|
||||||
|
final String[] baudRates = getResources().getStringArray(R.array.baud_rates);
|
||||||
|
int pos = java.util.Arrays.asList(baudRates).indexOf(String.valueOf(baudRate));
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setTitle("Baud rate");
|
||||||
|
builder.setSingleChoiceItems(baudRates, pos, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int item) {
|
||||||
|
baudRate = Integer.valueOf(baudRates[item]);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);
|
||||||
|
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
|
||||||
|
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
|
||||||
|
listItems.clear();
|
||||||
|
for(UsbDevice device : usbManager.getDeviceList().values()) {
|
||||||
|
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
|
||||||
|
if(driver == null) {
|
||||||
|
driver = usbCustomProber.probeDevice(device);
|
||||||
|
}
|
||||||
|
if(driver != null) {
|
||||||
|
for(int port = 0; port < driver.getPorts().size(); port++)
|
||||||
|
listItems.add(new ListItem(device, port, driver));
|
||||||
|
} else {
|
||||||
|
listItems.add(new ListItem(device, 0, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
|
ListItem item = listItems.get(position-1);
|
||||||
|
if(item.driver == null) {
|
||||||
|
Toast.makeText(getActivity(), "no driver", Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt("device", item.device.getDeviceId());
|
||||||
|
args.putInt("port", item.port);
|
||||||
|
args.putInt("baud", baudRate);
|
||||||
|
Fragment fragment = new TerminalFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
getFragmentManager().beginTransaction().replace(R.id.fragment, fragment, "terminal").addToBackStack(null).commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.hoho.android.usbserial.examples;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||||
|
if (savedInstanceState == null)
|
||||||
|
getSupportFragmentManager().beginTransaction().add(R.id.fragment, new DevicesFragment(), "devices").commit();
|
||||||
|
else
|
||||||
|
onBackStackChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackStackChanged() {
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount()>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSupportNavigateUp() {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
if(intent.getAction().equals("android.hardware.usb.action.USB_DEVICE_ATTACHED")) {
|
||||||
|
TerminalFragment terminal = (TerminalFragment)getSupportFragmentManager().findFragmentByTag("terminal");
|
||||||
|
if (terminal != null)
|
||||||
|
terminal.status("USB device detected");
|
||||||
|
}
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,230 +0,0 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
||||||
* USA.
|
|
||||||
*
|
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.hoho.android.usbserial.examples;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
|
||||||
import android.hardware.usb.UsbManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.ScrollView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
|
||||||
import com.hoho.android.usbserial.util.HexDump;
|
|
||||||
import com.hoho.android.usbserial.util.SerialInputOutputManager;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitors a single {@link UsbSerialPort} instance, showing all data
|
|
||||||
* received.
|
|
||||||
*
|
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
|
||||||
*/
|
|
||||||
public class SerialConsoleActivity extends Activity {
|
|
||||||
|
|
||||||
private final String TAG = SerialConsoleActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Driver instance, passed in statically via
|
|
||||||
* {@link #show(Context, UsbSerialPort)}.
|
|
||||||
*
|
|
||||||
* <p/>
|
|
||||||
* This is a devious hack; it'd be cleaner to re-create the driver using
|
|
||||||
* arguments passed in with the {@link #startActivity(Intent)} intent. We
|
|
||||||
* can get away with it because both activities will run in the same
|
|
||||||
* process, and this is a simple demo.
|
|
||||||
*/
|
|
||||||
private static UsbSerialPort sPort = null;
|
|
||||||
|
|
||||||
private TextView mTitleTextView;
|
|
||||||
private TextView mDumpTextView;
|
|
||||||
private ScrollView mScrollView;
|
|
||||||
private CheckBox chkDTR;
|
|
||||||
private CheckBox chkRTS;
|
|
||||||
|
|
||||||
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
|
|
||||||
|
|
||||||
private SerialInputOutputManager mSerialIoManager;
|
|
||||||
|
|
||||||
private final SerialInputOutputManager.Listener mListener =
|
|
||||||
new SerialInputOutputManager.Listener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRunError(Exception e) {
|
|
||||||
Log.d(TAG, "Runner stopped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNewData(final byte[] data) {
|
|
||||||
SerialConsoleActivity.this.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
SerialConsoleActivity.this.updateReceivedData(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.serial_console);
|
|
||||||
mTitleTextView = (TextView) findViewById(R.id.demoTitle);
|
|
||||||
mDumpTextView = (TextView) findViewById(R.id.consoleText);
|
|
||||||
mScrollView = (ScrollView) findViewById(R.id.demoScroller);
|
|
||||||
chkDTR = (CheckBox) findViewById(R.id.checkBoxDTR);
|
|
||||||
chkRTS = (CheckBox) findViewById(R.id.checkBoxRTS);
|
|
||||||
|
|
||||||
chkDTR.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
||||||
try {
|
|
||||||
sPort.setDTR(isChecked);
|
|
||||||
}catch (IOException x){}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
chkRTS.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
||||||
try {
|
|
||||||
sPort.setRTS(isChecked);
|
|
||||||
}catch (IOException x){}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
stopIoManager();
|
|
||||||
if (sPort != null) {
|
|
||||||
try {
|
|
||||||
sPort.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
sPort = null;
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void showStatus(TextView theTextView, String theLabel, boolean theValue){
|
|
||||||
String msg = theLabel + ": " + (theValue ? "enabled" : "disabled") + "\n";
|
|
||||||
theTextView.append(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
Log.d(TAG, "Resumed, port=" + sPort);
|
|
||||||
if (sPort == null) {
|
|
||||||
mTitleTextView.setText("No serial device.");
|
|
||||||
} else {
|
|
||||||
final UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
|
||||||
|
|
||||||
UsbDeviceConnection connection = usbManager.openDevice(sPort.getDriver().getDevice());
|
|
||||||
if (connection == null) {
|
|
||||||
mTitleTextView.setText("Opening device failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
sPort.open(connection);
|
|
||||||
sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
|
||||||
|
|
||||||
showStatus(mDumpTextView, "CD - Carrier Detect", sPort.getCD());
|
|
||||||
showStatus(mDumpTextView, "CTS - Clear To Send", sPort.getCTS());
|
|
||||||
showStatus(mDumpTextView, "DSR - Data Set Ready", sPort.getDSR());
|
|
||||||
showStatus(mDumpTextView, "DTR - Data Terminal Ready", sPort.getDTR());
|
|
||||||
showStatus(mDumpTextView, "DSR - Data Set Ready", sPort.getDSR());
|
|
||||||
showStatus(mDumpTextView, "RI - Ring Indicator", sPort.getRI());
|
|
||||||
showStatus(mDumpTextView, "RTS - Request To Send", sPort.getRTS());
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
|
|
||||||
mTitleTextView.setText("Error opening device: " + e.getMessage());
|
|
||||||
try {
|
|
||||||
sPort.close();
|
|
||||||
} catch (IOException e2) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
sPort = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mTitleTextView.setText("Serial device: " + sPort.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
onDeviceStateChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopIoManager() {
|
|
||||||
if (mSerialIoManager != null) {
|
|
||||||
Log.i(TAG, "Stopping io manager ..");
|
|
||||||
mSerialIoManager.stop();
|
|
||||||
mSerialIoManager = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startIoManager() {
|
|
||||||
if (sPort != null) {
|
|
||||||
Log.i(TAG, "Starting io manager ..");
|
|
||||||
mSerialIoManager = new SerialInputOutputManager(sPort, mListener);
|
|
||||||
mExecutor.submit(mSerialIoManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onDeviceStateChange() {
|
|
||||||
stopIoManager();
|
|
||||||
startIoManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateReceivedData(byte[] data) {
|
|
||||||
final String message = "Read " + data.length + " bytes: \n"
|
|
||||||
+ HexDump.dumpHexString(data) + "\n\n";
|
|
||||||
mDumpTextView.append(message);
|
|
||||||
mScrollView.smoothScrollTo(0, mDumpTextView.getBottom());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the activity, using the supplied driver instance.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param driver
|
|
||||||
*/
|
|
||||||
static void show(Context context, UsbSerialPort port) {
|
|
||||||
sPort = port;
|
|
||||||
final Intent intent = new Intent(context, SerialConsoleActivity.class);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,315 @@
|
||||||
|
package com.hoho.android.usbserial.examples;
|
||||||
|
|
||||||
|
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 android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.method.ScrollingMovementMethod;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialDriver;
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialPort;
|
||||||
|
import com.hoho.android.usbserial.driver.UsbSerialProber;
|
||||||
|
import com.hoho.android.usbserial.util.HexDump;
|
||||||
|
import com.hoho.android.usbserial.util.SerialInputOutputManager;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class TerminalFragment extends Fragment implements SerialInputOutputManager.Listener {
|
||||||
|
|
||||||
|
private enum UsbPermission { Unknown, Requested, Granted, Denied };
|
||||||
|
|
||||||
|
private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
|
||||||
|
private static final int WRITE_WAIT_MILLIS = 2000;
|
||||||
|
|
||||||
|
private int deviceId, portNum, baudRate;
|
||||||
|
|
||||||
|
private BroadcastReceiver broadcastReceiver;
|
||||||
|
private Handler mainLooper;
|
||||||
|
private TextView receiveText;
|
||||||
|
private ControlLines controlLines;
|
||||||
|
|
||||||
|
private SerialInputOutputManager usbIoManager;
|
||||||
|
private UsbSerialPort usbSerialPort;
|
||||||
|
private UsbPermission usbPermission = UsbPermission.Unknown;
|
||||||
|
private boolean connected = false;
|
||||||
|
|
||||||
|
public TerminalFragment() {
|
||||||
|
broadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if(intent.getAction().equals(INTENT_ACTION_GRANT_USB)) {
|
||||||
|
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
|
||||||
|
? UsbPermission.Granted : UsbPermission.Denied;
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mainLooper = new Handler(Looper.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lifecycle
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
setRetainInstance(true);
|
||||||
|
deviceId = getArguments().getInt("device");
|
||||||
|
portNum = getArguments().getInt("port");
|
||||||
|
baudRate = getArguments().getInt("baud");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
getActivity().registerReceiver(broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
|
||||||
|
|
||||||
|
if(usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted)
|
||||||
|
mainLooper.post(this::connect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
if(connected) {
|
||||||
|
status("disconnected");
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
getActivity().unregisterReceiver(broadcastReceiver);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UI
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_terminal, container, false);
|
||||||
|
receiveText = view.findViewById(R.id.receive_text); // TextView performance decreases with number of spans
|
||||||
|
receiveText.setTextColor(getResources().getColor(R.color.colorRecieveText)); // set as default color to reduce number of spans
|
||||||
|
receiveText.setMovementMethod(ScrollingMovementMethod.getInstance());
|
||||||
|
TextView sendText = view.findViewById(R.id.send_text);
|
||||||
|
View sendBtn = view.findViewById(R.id.send_btn);
|
||||||
|
sendBtn.setOnClickListener(v -> send(sendText.getText().toString()));
|
||||||
|
controlLines = new ControlLines(view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.menu_terminal, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == R.id.clear) {
|
||||||
|
receiveText.setText("");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onNewData(byte[] data) {
|
||||||
|
mainLooper.post(() -> {
|
||||||
|
receive(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRunError(Exception e) {
|
||||||
|
mainLooper.post(() -> {
|
||||||
|
status("connection lost: " + e.getMessage());
|
||||||
|
disconnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial + UI
|
||||||
|
*/
|
||||||
|
private void connect() {
|
||||||
|
UsbDevice device = null;
|
||||||
|
UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);
|
||||||
|
for(UsbDevice v : usbManager.getDeviceList().values())
|
||||||
|
if(v.getDeviceId() == deviceId)
|
||||||
|
device = v;
|
||||||
|
if(device == null) {
|
||||||
|
status("connection failed: device not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
|
||||||
|
if(driver == null) {
|
||||||
|
driver = CustomProber.getCustomProber().probeDevice(device);
|
||||||
|
}
|
||||||
|
if(driver == null) {
|
||||||
|
status("connection failed: no driver for device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(driver.getPorts().size() < portNum) {
|
||||||
|
status("connection failed: not enough ports at device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usbSerialPort = driver.getPorts().get(portNum);
|
||||||
|
UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
|
||||||
|
if(usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
|
||||||
|
usbPermission = UsbPermission.Requested;
|
||||||
|
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(getActivity(), 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
|
||||||
|
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(usbConnection == null) {
|
||||||
|
if (!usbManager.hasPermission(driver.getDevice()))
|
||||||
|
status("connection failed: permission denied");
|
||||||
|
else
|
||||||
|
status("connection failed: open failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
usbSerialPort.open(usbConnection);
|
||||||
|
usbSerialPort.setParameters(baudRate, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
||||||
|
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
|
||||||
|
Executors.newSingleThreadExecutor().submit(usbIoManager);
|
||||||
|
status("connected");
|
||||||
|
connected = true;
|
||||||
|
controlLines.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
status("connection failed: " + e.getMessage());
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disconnect() {
|
||||||
|
connected = false;
|
||||||
|
controlLines.stop();
|
||||||
|
if(usbIoManager != null)
|
||||||
|
usbIoManager.stop();
|
||||||
|
usbIoManager = null;
|
||||||
|
try {
|
||||||
|
usbSerialPort.close();
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
usbSerialPort = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send(String str) {
|
||||||
|
if(!connected) {
|
||||||
|
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
byte[] data = (str + '\n').getBytes();
|
||||||
|
SpannableStringBuilder spn = new SpannableStringBuilder();
|
||||||
|
spn.append("send " + data.length + " bytes:\n");
|
||||||
|
spn.append(HexDump.dumpHexString(data)+"\n");
|
||||||
|
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
receiveText.append(spn);
|
||||||
|
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
onRunError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receive(byte[] data) {
|
||||||
|
String str = new String(data);
|
||||||
|
SpannableStringBuilder spn = new SpannableStringBuilder();
|
||||||
|
spn.append("receive " + data.length + " bytes:\n");
|
||||||
|
spn.append(HexDump.dumpHexString(data)+"\n");
|
||||||
|
receiveText.append(spn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void status(String str) {
|
||||||
|
SpannableStringBuilder spn = new SpannableStringBuilder(str+'\n');
|
||||||
|
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorStatusText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
receiveText.append(spn);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ControlLines {
|
||||||
|
private static final int refreshInterval = 200; // msec
|
||||||
|
|
||||||
|
private Runnable runnable;
|
||||||
|
private ToggleButton rtsBtn, ctsBtn, dtrBtn, dsrBtn, cdBtn, riBtn;
|
||||||
|
|
||||||
|
ControlLines(View view) {
|
||||||
|
runnable = this::start; // w/o explicit Runnable, a new lambda would be created on each postDelayed, which would not be found again by removeCallbacks
|
||||||
|
|
||||||
|
rtsBtn = view.findViewById(R.id.controlLineRts);
|
||||||
|
ctsBtn = view.findViewById(R.id.controlLineCts);
|
||||||
|
dtrBtn = view.findViewById(R.id.controlLineDtr);
|
||||||
|
dsrBtn = view.findViewById(R.id.controlLineDsr);
|
||||||
|
cdBtn = view.findViewById(R.id.controlLineCd);
|
||||||
|
riBtn = view.findViewById(R.id.controlLineRi);
|
||||||
|
rtsBtn.setOnClickListener(this::toggle);
|
||||||
|
dtrBtn.setOnClickListener(this::toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggle(View v) {
|
||||||
|
ToggleButton btn = (ToggleButton) v;
|
||||||
|
if (!connected) {
|
||||||
|
btn.setChecked(!btn.isChecked());
|
||||||
|
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String ctrl = "";
|
||||||
|
try {
|
||||||
|
if (btn.equals(rtsBtn)) { ctrl = "RTS"; usbSerialPort.setRTS(btn.isChecked()); }
|
||||||
|
if (btn.equals(dtrBtn)) { ctrl = "DTR"; usbSerialPort.setDTR(btn.isChecked()); }
|
||||||
|
} catch (IOException e) {
|
||||||
|
status("set" + ctrl + " failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean refresh() {
|
||||||
|
String ctrl = "";
|
||||||
|
try {
|
||||||
|
ctrl = "RTS"; rtsBtn.setChecked(usbSerialPort.getRTS());
|
||||||
|
ctrl = "CTS"; ctsBtn.setChecked(usbSerialPort.getCTS());
|
||||||
|
ctrl = "DTR"; dtrBtn.setChecked(usbSerialPort.getDTR());
|
||||||
|
ctrl = "DSR"; dsrBtn.setChecked(usbSerialPort.getDSR());
|
||||||
|
ctrl = "CD"; cdBtn.setChecked(usbSerialPort.getCD());
|
||||||
|
ctrl = "RI"; riBtn.setChecked(usbSerialPort.getRI());
|
||||||
|
} catch (IOException e) {
|
||||||
|
status("get" + ctrl + " failed: " + e.getMessage() + " -> stopped control line refresh");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
if (connected && refresh())
|
||||||
|
mainLooper.postDelayed(runnable, refreshInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
mainLooper.removeCallbacks(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package com.hoho.android.usbserial.util;
|
package com.hoho.android.usbserial.util;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone of Android's HexDump class, for use in debugging. Cosmetic changes
|
* Clone of Android's HexDump class, for use in debugging. Cosmetic changes
|
||||||
* only.
|
* only.
|
||||||
|
@ -32,17 +34,12 @@ public class HexDump {
|
||||||
public static String dumpHexString(byte[] array, int offset, int length) {
|
public static String dumpHexString(byte[] array, int offset, int length) {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
|
|
||||||
byte[] line = new byte[16];
|
byte[] line = new byte[8];
|
||||||
int lineIndex = 0;
|
int lineIndex = 0;
|
||||||
|
|
||||||
result.append("\n0x");
|
|
||||||
result.append(toHexString(offset));
|
|
||||||
|
|
||||||
for (int i = offset; i < offset + length; i++) {
|
for (int i = offset; i < offset + length; i++) {
|
||||||
if (lineIndex == 16) {
|
if (lineIndex == line.length) {
|
||||||
result.append(" ");
|
for (int j = 0; j < line.length; j++) {
|
||||||
|
|
||||||
for (int j = 0; j < 16; j++) {
|
|
||||||
if (line[j] > ' ' && line[j] < '~') {
|
if (line[j] > ' ' && line[j] < '~') {
|
||||||
result.append(new String(line, j, 1));
|
result.append(new String(line, j, 1));
|
||||||
} else {
|
} else {
|
||||||
|
@ -50,32 +47,26 @@ public class HexDump {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append("\n0x");
|
result.append("\n");
|
||||||
result.append(toHexString(i));
|
|
||||||
lineIndex = 0;
|
lineIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte b = array[i];
|
byte b = array[i];
|
||||||
result.append(" ");
|
|
||||||
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
|
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
|
||||||
result.append(HEX_DIGITS[b & 0x0F]);
|
result.append(HEX_DIGITS[b & 0x0F]);
|
||||||
|
result.append(" ");
|
||||||
|
|
||||||
line[lineIndex++] = b;
|
line[lineIndex++] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lineIndex != 16) {
|
for (int i = 0; i < (line.length - lineIndex); i++) {
|
||||||
int count = (16 - lineIndex) * 3;
|
result.append(" ");
|
||||||
count++;
|
}
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < lineIndex; i++) {
|
||||||
result.append(" ");
|
if (line[i] > ' ' && line[i] < '~') {
|
||||||
}
|
result.append(new String(line, i, 1));
|
||||||
|
} else {
|
||||||
for (int i = 0; i < lineIndex; i++) {
|
result.append(".");
|
||||||
if (line[i] > ' ' && line[i] < '~') {
|
|
||||||
result.append(new String(line, i, 1));
|
|
||||||
} else {
|
|
||||||
result.append(".");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +136,7 @@ public class HexDump {
|
||||||
if (c >= 'a' && c <= 'f')
|
if (c >= 'a' && c <= 'f')
|
||||||
return (c - 'a' + 10);
|
return (c - 'a' + 10);
|
||||||
|
|
||||||
throw new RuntimeException("Invalid hex char '" + c + "'");
|
throw new InvalidParameterException("Invalid hex char '" + c + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] hexStringToByteArray(String hexString) {
|
public static byte[] hexStringToByteArray(String hexString) {
|
||||||
|
|
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/fragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/devices"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text1"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text2"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,122 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineRts"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:textOff="RTS"
|
||||||
|
android:textOn="RTS" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineCts"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:textColor="@android:color/secondary_text_dark"
|
||||||
|
android:textOff="CTS"
|
||||||
|
android:textOn="CTS" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="6dp" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineDtr"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:textOff="DTR"
|
||||||
|
android:textOn="DTR" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineDsr"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:textColor="@android:color/secondary_text_dark"
|
||||||
|
android:textOff="DSR"
|
||||||
|
android:textOn="DSR" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="6dp" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineCd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:textColor="@android:color/secondary_text_dark"
|
||||||
|
android:textOff="CD"
|
||||||
|
android:textOn="CD" />
|
||||||
|
|
||||||
|
<ToggleButton
|
||||||
|
android:id="@+id/controlLineRi"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="48sp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:textColor="@android:color/secondary_text_dark"
|
||||||
|
android:textOff="RI"
|
||||||
|
android:textOn="RI" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
android:layout_height="2dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/receive_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:freezesText="true"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:typeface="monospace" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
android:layout_height="2dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/send_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:inputType="text|textNoSuggestions"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/send_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:srcCompat="@drawable/ic_send_white_24dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/demoTitle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:text="@string/app_title"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/progressBarTitle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/demoTitle"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:text="@string/refreshing"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:textSize="18sp" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/progressBarTitle"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:padding="8dp"
|
|
||||||
style="@android:style/Widget.Holo.ProgressBar.Horizontal"
|
|
||||||
android:indeterminate="true" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/separator"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:layout_below="@+id/progressBar"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:background="#eeeeee" />
|
|
||||||
|
|
||||||
<ListView
|
|
||||||
android:id="@+id/deviceList"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/separator" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" >
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/demoTitle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:text="@string/app_title"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/separator"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:background="#eeeeee" />
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/textBtnDTR"
|
|
||||||
android:id="@+id/checkBoxDTR" />
|
|
||||||
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/textBtnRTS"
|
|
||||||
android:id="@+id/checkBoxRTS" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/separator2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_below="@+id/demoTitle"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:background="#eeeeee" />
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/demoScroller"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/consoleText"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:typeface="monospace" />
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/refresh"
|
||||||
|
android:title="Refresh devices" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/baud_rate"
|
||||||
|
android:title="Baud rate" />
|
||||||
|
</menu>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/clear"
|
||||||
|
android:icon="@drawable/ic_delete_white_24dp"
|
||||||
|
android:title="Clear"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</menu>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 895 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string-array name="baud_rates">
|
||||||
|
<item>2400</item>
|
||||||
|
<item>9600</item>
|
||||||
|
<item>19200</item>
|
||||||
|
<item>57600</item>
|
||||||
|
<item>115200</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#949C29</color>
|
||||||
|
<color name="colorPrimaryDark">#61671B</color>
|
||||||
|
<color name="colorAccent">#D8E33B</color>
|
||||||
|
|
||||||
|
<color name="colorRecieveText">#00FF00</color>
|
||||||
|
<color name="colorSendText">#82CAFF</color>
|
||||||
|
<color name="colorStatusText">#FFDB58</color>
|
||||||
|
</resources>
|
|
@ -1,10 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="app_title">USB Serial For Android Example</string>
|
||||||
<string name="app_title">USB Serial Example</string>
|
<string name="app_name">USB Serial Example</string>
|
||||||
<string name="app_name">Serial Example</string>
|
<string name="devices">USB Devices</string>
|
||||||
<string name="refreshing">Refreshing...</string>
|
|
||||||
<string name="textBtnRTS">RTS - Request To Send</string>
|
|
||||||
<string name="textBtnDTR">DTR - Data Terminal Ready</string>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|