├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── github │ │ └── jp1017 │ │ └── android_serial_port │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── jp1017 │ │ │ └── android_serial_port │ │ │ ├── SerialPort.java │ │ │ ├── SerialPortFinder.java │ │ │ └── sample │ │ │ ├── Application.java │ │ │ ├── ConsoleActivity.java │ │ │ ├── LoopbackActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── Sending0101Activity.java │ │ │ ├── SerialPortActivity.java │ │ │ └── SerialPortPreferences.java │ ├── jni │ │ ├── Android.mk │ │ ├── Application.mk │ │ ├── SerialPort.c │ │ └── gen_SerialPort_h.sh │ └── res │ │ ├── drawable │ │ └── icon.png │ │ ├── layout │ │ ├── activity_console.xml │ │ ├── activity_loopback.xml │ │ ├── activity_main.xml │ │ └── activity_sending0101.xml │ │ ├── values │ │ ├── baudrates.xml │ │ └── strings.xml │ │ └── xml │ │ └── serial_port_preferences.xml │ └── test │ └── java │ └── io │ └── github │ └── jp1017 │ └── android_serial_port │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /captures 3 | 4 | # Built application files 5 | *.apk 6 | *.ap_ 7 | 8 | # Files for the Dalvik VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | .idea 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | 19 | # Gradle files 20 | .gradle/ 21 | build/ 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Proguard folder generated by Eclipse 27 | proguard/ 28 | 29 | # Log Files 30 | *.log 31 | 32 | # iml files 33 | *.iml -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Android_Serial_Port -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 26 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Android Lint 46 | 47 | 48 | Java 49 | 50 | 51 | Java language level migration aidsJava 52 | 53 | 54 | Performance issuesJava 55 | 56 | 57 | Portability issuesJava 58 | 59 | 60 | Probable bugsJava 61 | 62 | 63 | 64 | 65 | Android 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 1.8 92 | 93 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidSerialPortSample 2 | 安卓串口示例,打开、接收、发送、关闭 3 | 4 | 来自:[android-serialport-api](https://code.google.com/archive/p/android-serialport-api/) 5 | 6 | 本人把项目移植到 `android studio` 7 | 8 | 直接下载: [**点我下载**](https://github.com/jp1017/AndroidSerialPortSample/releases/tag/v1.1) 9 | 10 | 测试的话,需要有自己开发板,现在一般手机都没有预留的串口 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | !/build/outputs/mapping/release/* 3 | *.iml -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def releaseTime() { 4 | return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) 5 | } 6 | 7 | android { 8 | compileSdkVersion 19 9 | buildToolsVersion "23.0.2" 10 | 11 | defaultConfig { 12 | applicationId "io.github.jp1017.android_serial_port" 13 | minSdkVersion 15 14 | targetSdkVersion 19 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | ndk { 19 | moduleName "serial_port" 20 | ldLibs "log" 21 | } 22 | } 23 | 24 | splits { 25 | abi { 26 | enable true 27 | reset() 28 | include 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86' //select ABIs to build APKs for 29 | universalApk true //generate an additional APK that contains all the ABIs 30 | } 31 | } 32 | 33 | // map for the version code 34 | // project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9] 35 | 36 | /* android.applicationVariants.all { variant -> 37 | // assign different version code for each output 38 | variant.outputs.each { output -> 39 | output.versionCodeOverride = 40 | project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode 41 | } 42 | }*/ 43 | 44 | //自定义apk安装包名 45 | applicationVariants.all { variant -> 46 | variant.outputs.each { output -> 47 | output.outputFile = new File( 48 | output.outputFile.parent + "/${variant.buildType.name}", 49 | "Android_Serial_Port-${variant.buildType.name}-${variant.versionCode}-${variant.versionName}-${variant.productFlavors[0].name}-${releaseTime()}.apk".toLowerCase()) 50 | } 51 | } 52 | 53 | productFlavors { 54 | armeabi { 55 | ndk { 56 | abiFilter "armeabi" 57 | } 58 | } 59 | armeabi_v7a { 60 | ndk { 61 | abiFilter "armeabi-v7a" 62 | } 63 | } 64 | arm64_v8a { 65 | ndk { 66 | abiFilter "arm64-v8a" 67 | } 68 | } 69 | x86 { 70 | ndk { 71 | abiFilter "x86" 72 | } 73 | } 74 | 75 | x86_64 { 76 | ndk { 77 | abiFilter "x86_64" 78 | } 79 | } 80 | } 81 | 82 | buildTypes { 83 | release { 84 | minifyEnabled false 85 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 86 | } 87 | } 88 | compileOptions { 89 | sourceCompatibility JavaVersion.VERSION_1_7 90 | targetCompatibility JavaVersion.VERSION_1_7 91 | } 92 | } 93 | 94 | dependencies { 95 | compile fileTree(include: ['*.jar'], dir: 'libs') 96 | testCompile 'junit:junit:4.12' 97 | } 98 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/io/github/jp1017/android_serial_port/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.github.jp1017.android_serial_port; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/jp1017/android_serial_port/SerialPort.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.jp1017.android_serial_port; 18 | 19 | import java.io.File; 20 | import java.io.FileDescriptor; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.io.OutputStream; 26 | 27 | import android.util.Log; 28 | 29 | public class SerialPort { 30 | 31 | private static final String TAG = "SerialPort"; 32 | 33 | /* 34 | * Do not remove or rename the field mFd: it is used by native method close(); 35 | */ 36 | private FileDescriptor mFd; 37 | private FileInputStream mFileInputStream; 38 | private FileOutputStream mFileOutputStream; 39 | 40 | public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { 41 | 42 | /* Check access permission */ 43 | if (!device.canRead() || !device.canWrite()) { 44 | try { 45 | /* Missing read/write permission, trying to chmod the file */ 46 | Process su; 47 | su = Runtime.getRuntime().exec("/system/bin/su"); 48 | String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" 49 | + "exit\n"; 50 | su.getOutputStream().write(cmd.getBytes()); 51 | if ((su.waitFor() != 0) || !device.canRead() 52 | || !device.canWrite()) { 53 | throw new SecurityException(); 54 | } 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | throw new SecurityException(); 58 | } 59 | } 60 | 61 | mFd = open(device.getAbsolutePath(), baudrate, flags); 62 | if (mFd == null) { 63 | Log.e(TAG, "native open returns null"); 64 | throw new IOException(); 65 | } 66 | mFileInputStream = new FileInputStream(mFd); 67 | mFileOutputStream = new FileOutputStream(mFd); 68 | } 69 | 70 | // Getters and setters 71 | public InputStream getInputStream() { 72 | return mFileInputStream; 73 | } 74 | 75 | public OutputStream getOutputStream() { 76 | return mFileOutputStream; 77 | } 78 | 79 | // JNI 80 | private native static FileDescriptor open(String path, int baudrate, int flags); 81 | public native void close(); 82 | static { 83 | System.loadLibrary("serial_port"); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/jp1017/android_serial_port/SerialPortFinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.jp1017.android_serial_port; 18 | 19 | import java.io.File; 20 | import java.io.FileReader; 21 | import java.io.IOException; 22 | import java.io.LineNumberReader; 23 | import java.util.Iterator; 24 | import java.util.Vector; 25 | 26 | import android.util.Log; 27 | 28 | public class SerialPortFinder { 29 | private static final String TAG = "SerialPort"; 30 | private Vector mDrivers = null; 31 | 32 | public class Driver { 33 | private String mDriverName; 34 | private String mDeviceRoot; 35 | Vector mDevices = null; 36 | 37 | public Driver(String name, String root) { 38 | mDriverName = name; 39 | mDeviceRoot = root; 40 | } 41 | 42 | public Vector getDevices() { 43 | if (mDevices == null) { 44 | mDevices = new Vector(); 45 | File dev = new File("/dev"); 46 | File[] files = dev.listFiles(); 47 | int i; 48 | for (i=0; i getDrivers() throws IOException { 63 | if (mDrivers == null) { 64 | mDrivers = new Vector<>(); 65 | LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers")); 66 | String l; 67 | while((l = r.readLine()) != null) { 68 | // Issue 3: 69 | // Since driver name may contain spaces, we do not extract driver name with split() 70 | String drivername = l.substring(0, 0x15).trim(); 71 | String[] w = l.split(" +"); 72 | if ((w.length >= 5) && (w[w.length-1].equals("serial"))) { 73 | Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]); 74 | mDrivers.add(new Driver(drivername, w[w.length-4])); 75 | } 76 | } 77 | r.close(); 78 | } 79 | return mDrivers; 80 | } 81 | 82 | public String[] getAllDevices() { 83 | Vector devices = new Vector(); 84 | // Parse each driver 85 | Iterator itdriv; 86 | try { 87 | itdriv = getDrivers().iterator(); 88 | while(itdriv.hasNext()) { 89 | Driver driver = itdriv.next(); 90 | Iterator itdev = driver.getDevices().iterator(); 91 | while(itdev.hasNext()) { 92 | String device = itdev.next().getName(); 93 | String value = String.format("%s (%s)", device, driver.getName()); 94 | devices.add(value); 95 | } 96 | } 97 | } catch (IOException e) { 98 | e.printStackTrace(); 99 | } 100 | return devices.toArray(new String[devices.size()]); 101 | } 102 | 103 | public String[] getAllDevicesPath() { 104 | Vector devices = new Vector(); 105 | // Parse each driver 106 | Iterator itdriv; 107 | try { 108 | itdriv = getDrivers().iterator(); 109 | while(itdriv.hasNext()) { 110 | Driver driver = itdriv.next(); 111 | Iterator itdev = driver.getDevices().iterator(); 112 | while(itdev.hasNext()) { 113 | String device = itdev.next().getAbsolutePath(); 114 | devices.add(device); 115 | } 116 | } 117 | } catch (IOException e) { 118 | e.printStackTrace(); 119 | } 120 | return devices.toArray(new String[devices.size()]); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/jp1017/android_serial_port/sample/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.jp1017.android_serial_port.sample; 18 | 19 | import android.content.SharedPreferences; 20 | import android.util.Log; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.security.InvalidParameterException; 25 | 26 | import io.github.jp1017.android_serial_port.SerialPort; 27 | import io.github.jp1017.android_serial_port.SerialPortFinder; 28 | 29 | public class Application extends android.app.Application { 30 | private final static String TAG = "LOOO"; 31 | 32 | public SerialPortFinder mSerialPortFinder = new SerialPortFinder(); 33 | private SerialPort mSerialPort = null; 34 | 35 | public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException { 36 | if (mSerialPort == null) { 37 | /* Read serial port parameters */ 38 | SharedPreferences sp = getSharedPreferences("io.github.jp1017.android_serial_port_preferences", MODE_PRIVATE); 39 | 40 | String path = sp.getString("DEVICE", ""); 41 | 42 | int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1")); 43 | 44 | /* Check parameters */ 45 | Log.i(TAG, "length: " + path.length() + "baudrate: " + baudrate); 46 | 47 | if ( (path.length() == 0) || (baudrate == -1)) { 48 | throw new InvalidParameterException(); 49 | } 50 | 51 | /* Open the serial port */ 52 | mSerialPort = new SerialPort(new File(path), baudrate, 0); 53 | } 54 | return mSerialPort; 55 | } 56 | 57 | public void closeSerialPort() { 58 | if (mSerialPort != null) { 59 | mSerialPort.close(); 60 | mSerialPort = null; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/jp1017/android_serial_port/sample/ConsoleActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.jp1017.android_serial_port.sample; 18 | 19 | import android.os.Bundle; 20 | import android.view.KeyEvent; 21 | import android.widget.EditText; 22 | import android.widget.TextView; 23 | import android.widget.TextView.OnEditorActionListener; 24 | 25 | import java.io.IOException; 26 | 27 | import io.github.jp1017.android_serial_port.R; 28 | 29 | 30 | public class ConsoleActivity extends SerialPortActivity { 31 | 32 | EditText mReception; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_console); 38 | 39 | // setTitle("Loopback test"); 40 | mReception = (EditText) findViewById(R.id.EditTextReception); 41 | 42 | EditText Emission = (EditText) findViewById(R.id.EditTextEmission); 43 | Emission.setOnEditorActionListener(new OnEditorActionListener() { 44 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 45 | int i; 46 | CharSequence t = v.getText(); 47 | char[] text = new char[t.length()]; 48 | for (i=0; i 0) { 54 | onDataReceived(buffer, size); 55 | } 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | return; 59 | } 60 | } 61 | } 62 | } 63 | 64 | @Override 65 | protected void onCreate(Bundle savedInstanceState) { 66 | super.onCreate(savedInstanceState); 67 | mApplication = (Application) getApplication(); 68 | try { 69 | mSerialPort = mApplication.getSerialPort(); 70 | mOutputStream = mSerialPort.getOutputStream(); 71 | mInputStream = mSerialPort.getInputStream(); 72 | 73 | /* Create a receiving thread */ 74 | mReadThread = new ReadThread(); 75 | mReadThread.start(); 76 | } catch (SecurityException e) { 77 | DisplayError(R.string.error_security); 78 | } catch (IOException e) { 79 | DisplayError(R.string.error_unknown); 80 | } catch (InvalidParameterException e) { 81 | DisplayError(R.string.error_configuration); 82 | } 83 | } 84 | 85 | @Override 86 | protected void onDestroy() { 87 | if (mReadThread != null) 88 | mReadThread.interrupt(); 89 | mApplication.closeSerialPort(); 90 | mSerialPort = null; 91 | super.onDestroy(); 92 | } 93 | 94 | private void DisplayError(int resourceId) { 95 | AlertDialog.Builder b = new AlertDialog.Builder(this); 96 | b.setTitle("Error"); 97 | b.setMessage(resourceId); 98 | b.setPositiveButton("OK", new OnClickListener() { 99 | public void onClick(DialogInterface dialog, int which) { 100 | SerialPortActivity.this.finish(); 101 | } 102 | }); 103 | b.show(); 104 | } 105 | 106 | protected abstract void onDataReceived(final byte[] buffer, final int size); 107 | 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/jp1017/android_serial_port/sample/SerialPortPreferences.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.jp1017.android_serial_port.sample; 18 | 19 | import android.os.Bundle; 20 | import android.preference.ListPreference; 21 | import android.preference.Preference; 22 | import android.preference.Preference.OnPreferenceChangeListener; 23 | import android.preference.PreferenceActivity; 24 | 25 | import io.github.jp1017.android_serial_port.R; 26 | import io.github.jp1017.android_serial_port.SerialPortFinder; 27 | 28 | public class SerialPortPreferences extends PreferenceActivity { 29 | 30 | private Application mApplication; 31 | private SerialPortFinder mSerialPortFinder; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | 37 | mApplication = (Application) getApplication(); 38 | mSerialPortFinder = mApplication.mSerialPortFinder; 39 | 40 | addPreferencesFromResource(R.xml.serial_port_preferences); 41 | 42 | // Devices 43 | final ListPreference devices = (ListPreference)findPreference("DEVICE"); 44 | String[] entries = mSerialPortFinder.getAllDevices(); 45 | String[] entryValues = mSerialPortFinder.getAllDevicesPath(); 46 | devices.setEntries(entries); 47 | devices.setEntryValues(entryValues); 48 | devices.setSummary(devices.getValue()); 49 | devices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 50 | public boolean onPreferenceChange(Preference preference, Object newValue) { 51 | preference.setSummary((String)newValue); 52 | return true; 53 | } 54 | }); 55 | 56 | // Baud rates 57 | final ListPreference baudrates = (ListPreference)findPreference("BAUDRATE"); 58 | baudrates.setSummary(baudrates.getValue()); 59 | baudrates.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 60 | public boolean onPreferenceChange(Preference preference, Object newValue) { 61 | preference.setSummary((String)newValue); 62 | return true; 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2009 Cedric Priscal 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | LOCAL_PATH := $(call my-dir) 18 | 19 | include $(CLEAR_VARS) 20 | 21 | TARGET_PLATFORM := android-3 22 | LOCAL_MODULE := serial_port 23 | LOCAL_SRC_FILES := SerialPort.c 24 | LOCAL_LDLIBS := -llog 25 | 26 | include $(BUILD_SHARED_LIBRARY) 27 | -------------------------------------------------------------------------------- /app/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi armeabi-v7a x86 2 | -------------------------------------------------------------------------------- /app/src/main/jni/SerialPort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2011 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "android/log.h" 26 | static const char *TAG="serial_port"; 27 | #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) 28 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) 29 | #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) 30 | 31 | static speed_t getBaudrate(jint baudrate) 32 | { 33 | switch(baudrate) { 34 | case 0: return B0; 35 | case 50: return B50; 36 | case 75: return B75; 37 | case 110: return B110; 38 | case 134: return B134; 39 | case 150: return B150; 40 | case 200: return B200; 41 | case 300: return B300; 42 | case 600: return B600; 43 | case 1200: return B1200; 44 | case 1800: return B1800; 45 | case 2400: return B2400; 46 | case 4800: return B4800; 47 | case 9600: return B9600; 48 | case 19200: return B19200; 49 | case 38400: return B38400; 50 | case 57600: return B57600; 51 | case 115200: return B115200; 52 | case 230400: return B230400; 53 | case 460800: return B460800; 54 | case 500000: return B500000; 55 | case 576000: return B576000; 56 | case 921600: return B921600; 57 | case 1000000: return B1000000; 58 | case 1152000: return B1152000; 59 | case 1500000: return B1500000; 60 | case 2000000: return B2000000; 61 | case 2500000: return B2500000; 62 | case 3000000: return B3000000; 63 | case 3500000: return B3500000; 64 | case 4000000: return B4000000; 65 | default: return -1; 66 | } 67 | } 68 | 69 | /* 70 | * Class: android_serialport_SerialPort 71 | * Method: open 72 | * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 73 | */ 74 | JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open 75 | (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) 76 | { 77 | int fd; 78 | speed_t speed; 79 | jobject mFileDescriptor; 80 | 81 | /* Check arguments */ 82 | { 83 | speed = getBaudrate(baudrate); 84 | if (speed == -1) { 85 | /* TODO: throw an exception */ 86 | LOGE("Invalid baudrate"); 87 | return NULL; 88 | } 89 | } 90 | 91 | /* Opening device */ 92 | { 93 | jboolean iscopy; 94 | const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); 95 | LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); 96 | fd = open(path_utf, O_RDWR | flags); 97 | LOGD("open() fd = %d", fd); 98 | (*env)->ReleaseStringUTFChars(env, path, path_utf); 99 | if (fd == -1) 100 | { 101 | /* Throw an exception */ 102 | LOGE("Cannot open port"); 103 | /* TODO: throw an exception */ 104 | return NULL; 105 | } 106 | } 107 | 108 | /* Configure device */ 109 | { 110 | struct termios cfg; 111 | LOGD("Configuring serial port"); 112 | if (tcgetattr(fd, &cfg)) 113 | { 114 | LOGE("tcgetattr() failed"); 115 | close(fd); 116 | /* TODO: throw an exception */ 117 | return NULL; 118 | } 119 | 120 | cfmakeraw(&cfg); 121 | cfsetispeed(&cfg, speed); 122 | cfsetospeed(&cfg, speed); 123 | 124 | if (tcsetattr(fd, TCSANOW, &cfg)) 125 | { 126 | LOGE("tcsetattr() failed"); 127 | close(fd); 128 | /* TODO: throw an exception */ 129 | return NULL; 130 | } 131 | } 132 | 133 | /* Create a corresponding file descriptor */ 134 | { 135 | jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); 136 | jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); 137 | jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); 138 | mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); 139 | (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd); 140 | } 141 | 142 | return mFileDescriptor; 143 | } 144 | 145 | /* 146 | * Class: cedric_serial_SerialPort 147 | * Method: close 148 | * Signature: ()V 149 | */ 150 | JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close 151 | (JNIEnv *env, jobject thiz) 152 | { 153 | jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); 154 | jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); 155 | 156 | jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); 157 | jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); 158 | 159 | jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); 160 | jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); 161 | 162 | LOGD("close(fd = %d)", descriptor); 163 | close(descriptor); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /app/src/main/jni/gen_SerialPort_h.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | javah -o SerialPort.h -jni -classpath ../src android_serialport_api.SerialPort 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp1017/AndroidSerialPortSample/5145e29b6a73409ea30a7836e3ce30b3bb17f21c/app/src/main/res/drawable/icon.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_console.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_loopback.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 28 | 29 | 30 | 35 | 36 | 43 | 44 | 50 | 51 | 52 | 56 | 57 | 64 | 65 | 71 | 72 | 73 | 77 | 78 | 85 | 86 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |