├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── example ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── felhr │ │ └── serialportexample │ │ ├── MainActivity.java │ │ └── UsbService.java │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Key 16 | *.jks 17 | 18 | # Local configuration file (sdk path, etc) 19 | local.properties 20 | 21 | # Intellij project files 22 | *.iml 23 | *.ipr 24 | *.iws 25 | .idea/ 26 | *.prefs 27 | 28 | # Gradle 29 | build/ 30 | .gradle 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Felipe Herranz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SerialPortExample 2 | 3 | [THIS EXAMPLE IS VERY OUTDATED. PLEASE GO TO THE USBSERIAL REPO FOR BETTER EXAMPLES](https://github.com/felHR85/UsbSerial) 4 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.5.0' 7 | } 8 | } 9 | 10 | allprojects { 11 | repositories { 12 | jcenter() 13 | maven { url "https://jitpack.io" } 14 | } 15 | } 16 | 17 | task clean(type: Delete) { 18 | delete rootProject.buildDir 19 | } 20 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.jks 3 | signing.properties -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 6 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 7 | 8 | defaultConfig { 9 | applicationId "com.felhr.serialportexample" 10 | minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION) 11 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 12 | versionName project.VERSION_NAME 13 | versionCode Integer.parseInt(project.VERSION_CODE) 14 | } 15 | 16 | compileOptions { 17 | encoding "UTF-8" 18 | sourceCompatibility JavaVersion.VERSION_1_7 19 | targetCompatibility JavaVersion.VERSION_1_7 20 | } 21 | } 22 | 23 | dependencies { 24 | compile 'com.android.support:support-v4:23.1.1' 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | compile 'com.android.support:design:23.1.1' 27 | 28 | compile 'com.github.felHR85:UsbSerial:3.3' 29 | } 30 | -------------------------------------------------------------------------------- /example/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 C:\Program Files (x86)\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 | -------------------------------------------------------------------------------- /example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/src/main/java/com/felhr/serialportexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.felhr.serialportexample; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.IntentFilter; 8 | import android.content.ServiceConnection; 9 | import android.os.Bundle; 10 | import android.os.Handler; 11 | import android.os.IBinder; 12 | import android.os.Message; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.view.View; 15 | import android.widget.Button; 16 | import android.widget.EditText; 17 | import android.widget.TextView; 18 | import android.widget.Toast; 19 | 20 | import java.lang.ref.WeakReference; 21 | import java.util.Set; 22 | 23 | public class MainActivity extends AppCompatActivity { 24 | 25 | /* 26 | * Notifications from UsbService will be received here. 27 | */ 28 | private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 29 | @Override 30 | public void onReceive(Context context, Intent intent) { 31 | switch (intent.getAction()) { 32 | case UsbService.ACTION_USB_PERMISSION_GRANTED: // USB PERMISSION GRANTED 33 | Toast.makeText(context, "USB Ready", Toast.LENGTH_SHORT).show(); 34 | break; 35 | case UsbService.ACTION_USB_PERMISSION_NOT_GRANTED: // USB PERMISSION NOT GRANTED 36 | Toast.makeText(context, "USB Permission not granted", Toast.LENGTH_SHORT).show(); 37 | break; 38 | case UsbService.ACTION_NO_USB: // NO USB CONNECTED 39 | Toast.makeText(context, "No USB connected", Toast.LENGTH_SHORT).show(); 40 | break; 41 | case UsbService.ACTION_USB_DISCONNECTED: // USB DISCONNECTED 42 | Toast.makeText(context, "USB disconnected", Toast.LENGTH_SHORT).show(); 43 | break; 44 | case UsbService.ACTION_USB_NOT_SUPPORTED: // USB NOT SUPPORTED 45 | Toast.makeText(context, "USB device not supported", Toast.LENGTH_SHORT).show(); 46 | break; 47 | } 48 | } 49 | }; 50 | private UsbService usbService; 51 | private TextView display; 52 | private EditText editText; 53 | private MyHandler mHandler; 54 | private final ServiceConnection usbConnection = new ServiceConnection() { 55 | @Override 56 | public void onServiceConnected(ComponentName arg0, IBinder arg1) { 57 | usbService = ((UsbService.UsbBinder) arg1).getService(); 58 | usbService.setHandler(mHandler); 59 | } 60 | 61 | @Override 62 | public void onServiceDisconnected(ComponentName arg0) { 63 | usbService = null; 64 | } 65 | }; 66 | 67 | @Override 68 | protected void onCreate(Bundle savedInstanceState) { 69 | super.onCreate(savedInstanceState); 70 | setContentView(R.layout.activity_main); 71 | 72 | mHandler = new MyHandler(this); 73 | 74 | display = (TextView) findViewById(R.id.textView1); 75 | editText = (EditText) findViewById(R.id.editText1); 76 | Button sendButton = (Button) findViewById(R.id.buttonSend); 77 | sendButton.setOnClickListener(new View.OnClickListener() { 78 | @Override 79 | public void onClick(View v) { 80 | if (!editText.getText().toString().equals("")) { 81 | String data = editText.getText().toString(); 82 | if (usbService != null) { // if UsbService was correctly binded, Send data 83 | display.append(data); 84 | usbService.write(data.getBytes()); 85 | } 86 | } 87 | } 88 | }); 89 | } 90 | 91 | @Override 92 | public void onResume() { 93 | super.onResume(); 94 | setFilters(); // Start listening notifications from UsbService 95 | startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it 96 | } 97 | 98 | @Override 99 | public void onPause() { 100 | super.onPause(); 101 | unregisterReceiver(mUsbReceiver); 102 | unbindService(usbConnection); 103 | } 104 | 105 | private void startService(Class service, ServiceConnection serviceConnection, Bundle extras) { 106 | if (!UsbService.SERVICE_CONNECTED) { 107 | Intent startService = new Intent(this, service); 108 | if (extras != null && !extras.isEmpty()) { 109 | Set keys = extras.keySet(); 110 | for (String key : keys) { 111 | String extra = extras.getString(key); 112 | startService.putExtra(key, extra); 113 | } 114 | } 115 | startService(startService); 116 | } 117 | Intent bindingIntent = new Intent(this, service); 118 | bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE); 119 | } 120 | 121 | private void setFilters() { 122 | IntentFilter filter = new IntentFilter(); 123 | filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED); 124 | filter.addAction(UsbService.ACTION_NO_USB); 125 | filter.addAction(UsbService.ACTION_USB_DISCONNECTED); 126 | filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED); 127 | filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED); 128 | registerReceiver(mUsbReceiver, filter); 129 | } 130 | 131 | /* 132 | * This handler will be passed to UsbService. Data received from serial port is displayed through this handler 133 | */ 134 | private static class MyHandler extends Handler { 135 | private final WeakReference mActivity; 136 | 137 | public MyHandler(MainActivity activity) { 138 | mActivity = new WeakReference<>(activity); 139 | } 140 | 141 | @Override 142 | public void handleMessage(Message msg) { 143 | switch (msg.what) { 144 | case UsbService.MESSAGE_FROM_SERIAL_PORT: 145 | String data = (String) msg.obj; 146 | mActivity.get().display.append(data); 147 | break; 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /example/src/main/java/com/felhr/serialportexample/UsbService.java: -------------------------------------------------------------------------------- 1 | package com.felhr.serialportexample; 2 | 3 | import android.app.PendingIntent; 4 | import android.app.Service; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.hardware.usb.UsbDevice; 10 | import android.hardware.usb.UsbDeviceConnection; 11 | import android.hardware.usb.UsbManager; 12 | import android.os.Binder; 13 | import android.os.Handler; 14 | import android.os.IBinder; 15 | 16 | import com.felhr.usbserial.CDCSerialDevice; 17 | import com.felhr.usbserial.UsbSerialDevice; 18 | import com.felhr.usbserial.UsbSerialInterface; 19 | 20 | import java.io.UnsupportedEncodingException; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | public class UsbService extends Service { 25 | 26 | public static final String ACTION_USB_READY = "com.felhr.connectivityservices.USB_READY"; 27 | public static final String ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"; 28 | public static final String ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED"; 29 | public static final String ACTION_USB_NOT_SUPPORTED = "com.felhr.usbservice.USB_NOT_SUPPORTED"; 30 | public static final String ACTION_NO_USB = "com.felhr.usbservice.NO_USB"; 31 | public static final String ACTION_USB_PERMISSION_GRANTED = "com.felhr.usbservice.USB_PERMISSION_GRANTED"; 32 | public static final String ACTION_USB_PERMISSION_NOT_GRANTED = "com.felhr.usbservice.USB_PERMISSION_NOT_GRANTED"; 33 | public static final String ACTION_USB_DISCONNECTED = "com.felhr.usbservice.USB_DISCONNECTED"; 34 | public static final String ACTION_CDC_DRIVER_NOT_WORKING = "com.felhr.connectivityservices.ACTION_CDC_DRIVER_NOT_WORKING"; 35 | public static final String ACTION_USB_DEVICE_NOT_WORKING = "com.felhr.connectivityservices.ACTION_USB_DEVICE_NOT_WORKING"; 36 | public static final int MESSAGE_FROM_SERIAL_PORT = 0; 37 | private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; 38 | private static final int BAUD_RATE = 9600; // BaudRate. Change this value if you need 39 | public static boolean SERVICE_CONNECTED = false; 40 | 41 | private IBinder binder = new UsbBinder(); 42 | 43 | private Context context; 44 | private Handler mHandler; 45 | private UsbManager usbManager; 46 | private UsbDevice device; 47 | private UsbDeviceConnection connection; 48 | private UsbSerialDevice serialPort; 49 | 50 | private boolean serialPortConnected; 51 | /* 52 | * Data received from serial port will be received here. Just populate onReceivedData with your code 53 | * In this particular example. byte stream is converted to String and send to UI thread to 54 | * be treated there. 55 | */ 56 | private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { 57 | @Override 58 | public void onReceivedData(byte[] arg0) { 59 | try { 60 | String data = new String(arg0, "UTF-8"); 61 | if (mHandler != null) 62 | mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT, data).sendToTarget(); 63 | } catch (UnsupportedEncodingException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | }; 68 | /* 69 | * Different notifications from OS will be received here (USB attached, detached, permission responses...) 70 | * About BroadcastReceiver: http://developer.android.com/reference/android/content/BroadcastReceiver.html 71 | */ 72 | private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { 73 | @Override 74 | public void onReceive(Context arg0, Intent arg1) { 75 | if (arg1.getAction().equals(ACTION_USB_PERMISSION)) { 76 | boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED); 77 | if (granted) // User accepted our USB connection. Try to open the device as a serial port 78 | { 79 | Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED); 80 | arg0.sendBroadcast(intent); 81 | connection = usbManager.openDevice(device); 82 | serialPortConnected = true; 83 | new ConnectionThread().run(); 84 | } else // User not accepted our USB connection. Send an Intent to the Main Activity 85 | { 86 | Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED); 87 | arg0.sendBroadcast(intent); 88 | } 89 | } else if (arg1.getAction().equals(ACTION_USB_ATTACHED)) { 90 | if (!serialPortConnected) 91 | findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port 92 | } else if (arg1.getAction().equals(ACTION_USB_DETACHED)) { 93 | // Usb device was disconnected. send an intent to the Main Activity 94 | Intent intent = new Intent(ACTION_USB_DISCONNECTED); 95 | arg0.sendBroadcast(intent); 96 | serialPortConnected = false; 97 | serialPort.close(); 98 | } 99 | } 100 | }; 101 | 102 | /* 103 | * onCreate will be executed when service is started. It configures an IntentFilter to listen for 104 | * incoming Intents (USB ATTACHED, USB DETACHED...) and it tries to open a serial port. 105 | */ 106 | @Override 107 | public void onCreate() { 108 | this.context = this; 109 | serialPortConnected = false; 110 | UsbService.SERVICE_CONNECTED = true; 111 | setFilter(); 112 | usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); 113 | findSerialPortDevice(); 114 | } 115 | 116 | /* MUST READ about services 117 | * http://developer.android.com/guide/components/services.html 118 | * http://developer.android.com/guide/components/bound-services.html 119 | */ 120 | @Override 121 | public IBinder onBind(Intent intent) { 122 | return binder; 123 | } 124 | 125 | @Override 126 | public int onStartCommand(Intent intent, int flags, int startId) { 127 | return Service.START_NOT_STICKY; 128 | } 129 | 130 | @Override 131 | public void onDestroy() { 132 | super.onDestroy(); 133 | UsbService.SERVICE_CONNECTED = false; 134 | } 135 | 136 | /* 137 | * This function will be called from MainActivity to write data through Serial Port 138 | */ 139 | public void write(byte[] data) { 140 | if (serialPort != null) 141 | serialPort.write(data); 142 | } 143 | 144 | public void setHandler(Handler mHandler) { 145 | this.mHandler = mHandler; 146 | } 147 | 148 | private void findSerialPortDevice() { 149 | // This snippet will try to open the first encountered usb device connected, excluding usb root hubs 150 | HashMap usbDevices = usbManager.getDeviceList(); 151 | if (!usbDevices.isEmpty()) { 152 | boolean keep = true; 153 | for (Map.Entry entry : usbDevices.entrySet()) { 154 | device = entry.getValue(); 155 | int deviceVID = device.getVendorId(); 156 | int devicePID = device.getProductId(); 157 | 158 | if (deviceVID != 0x1d6b && (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003)) { 159 | // There is a device connected to our Android device. Try to open it as a Serial Port. 160 | requestUserPermission(); 161 | keep = false; 162 | } else { 163 | connection = null; 164 | device = null; 165 | } 166 | 167 | if (!keep) 168 | break; 169 | } 170 | if (!keep) { 171 | // There is no USB devices connected (but usb host were listed). Send an intent to MainActivity. 172 | Intent intent = new Intent(ACTION_NO_USB); 173 | sendBroadcast(intent); 174 | } 175 | } else { 176 | // There is no USB devices connected. Send an intent to MainActivity 177 | Intent intent = new Intent(ACTION_NO_USB); 178 | sendBroadcast(intent); 179 | } 180 | } 181 | 182 | private void setFilter() { 183 | IntentFilter filter = new IntentFilter(); 184 | filter.addAction(ACTION_USB_PERMISSION); 185 | filter.addAction(ACTION_USB_DETACHED); 186 | filter.addAction(ACTION_USB_ATTACHED); 187 | registerReceiver(usbReceiver, filter); 188 | } 189 | 190 | /* 191 | * Request user permission. The response will be received in the BroadcastReceiver 192 | */ 193 | private void requestUserPermission() { 194 | PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); 195 | usbManager.requestPermission(device, mPendingIntent); 196 | } 197 | 198 | public class UsbBinder extends Binder { 199 | public UsbService getService() { 200 | return UsbService.this; 201 | } 202 | } 203 | 204 | /* 205 | * A simple thread to open a serial port. 206 | * Although it should be a fast operation. moving usb operations away from UI thread is a good thing. 207 | */ 208 | private class ConnectionThread extends Thread { 209 | @Override 210 | public void run() { 211 | serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection); 212 | if (serialPort != null) { 213 | if (serialPort.open()) { 214 | serialPort.setBaudRate(BAUD_RATE); 215 | serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8); 216 | serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1); 217 | serialPort.setParity(UsbSerialInterface.PARITY_NONE); 218 | serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF); 219 | serialPort.read(mCallback); 220 | 221 | // Everything went as expected. Send an intent to MainActivity 222 | Intent intent = new Intent(ACTION_USB_READY); 223 | context.sendBroadcast(intent); 224 | } else { 225 | // Serial port could not be opened, maybe an I/O error or if CDC driver was chosen, it does not really fit 226 | // Send an Intent to Main Activity 227 | if (serialPort instanceof CDCSerialDevice) { 228 | Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING); 229 | context.sendBroadcast(intent); 230 | } else { 231 | Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING); 232 | context.sendBroadcast(intent); 233 | } 234 | } 235 | } else { 236 | // No driver for given device, even generic CDC driver could not be loaded 237 | Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED); 238 | context.sendBroadcast(intent); 239 | } 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felHR85/SerialPortExample/b2c8250a67d8b98675c3ec97ae932c033ddc229f/example/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felHR85/SerialPortExample/b2c8250a67d8b98675c3ec97ae932c033ddc229f/example/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felHR85/SerialPortExample/b2c8250a67d8b98675c3ec97ae932c033ddc229f/example/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felHR85/SerialPortExample/b2c8250a67d8b98675c3ec97ae932c033ddc229f/example/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 27 | 28 | 37 | 38 | 39 | 40 | 41 |