Android Bluetooth Terminal

Posted on

The postal service inwards my about other blogspot demo how to “Config Raspberry Pi to role HC-06 Bluetooth Module, every bit Serial Terminal“.

My onetime postal service demo how “Android communicate amongst Arduino + HC-06 Bluetooth Module” to link Android amongst other series devices via bluetooth. Actually, it tin sack communicate amongst Raspberry Pi + HC-06 also.

This instance I re-code “Android communicate amongst Arduino + HC-06 Bluetooth Module” to larn inwards run similar a series terminal to log-in Raspberry Pi via bluetooth.

– Prepare on Raspberry Pi 2, to config series terminal run on 9600 baud, refer “Config Raspberry Pi to role HC-06 Bluetooth Module, every bit Serial Terminal“.
–  The Android in addition to HC-06 accept to duo inwards advance.


Create a novel projection of Blank Activity inwards Android Studio,

layout/content_main.xml, it’s the primary terminal screen.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout     xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     xmlns:app="http://schemas.android.com/apk/res-auto"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:padding="5dp"     android:orientation="vertical"     app:layout_behavior="@string/appbar_scrolling_view_behavior"     tools:showIn="@layout/activity_main"     tools:context=".MainActivity">      <TextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="center_horizontal"         android:autoLink="web"         android:text="https://rootandroid.org//"         android:textStyle="bold" />      <TextView         android:id="@+id/body"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:textColor="@android:color/white"         android:background="@android:color/black"         android:typeface="monospace"         android:gravity="bottom"/>  </LinearLayout>  

Edit layout/activity_main.xml, only to alter the icon of the FloatingActionButton.

<?xml version="1.0" encoding="utf-8"?> <android.support.design.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" android:fitsSystemWindows="true"     tools:context=".MainActivity">      <android.support.design.widget.AppBarLayout android:layout_height="wrap_content"         android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay">          <android.support.v7.widget.Toolbar android:id="@+id/toolbar"             android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"             android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" />      </android.support.design.widget.AppBarLayout>      <include layout="@layout/content_main" />      <android.support.design.widget.FloatingActionButton android:id="@+id/fab"         android:layout_width="wrap_content" android:layout_height="wrap_content"         android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin"         android:src="@android:drawable/ic_menu_edit" />  </android.support.design.widget.CoordinatorLayout>  

Create layout/setting_layout.xml, the layout of SettingDialog (OptionsMenu -> Setting), to listing paired bluetooth to connect.

<?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">      <ListView         android:id="@+id/pairedlist"         android:layout_width="match_parent"         android:layout_height="match_parent"/>  </LinearLayout> 

Create layout/typing_layout.xml, the layout of CmdLineDialog (open 1 time FloatingActionButton is clicked), for user to come inwards command.

<?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">       <LinearLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:orientation="horizontal">         <EditText             android:id="@+id/cmdline"             android:layout_weight="1"             android:layout_width="0dp"             android:layout_height="wrap_content" />          <ImageView             android:id="@+id/clearcmd"             android:layout_width="wrap_content"             android:src="@android:drawable/ic_menu_close_clear_cancel"             android:layout_height="wrap_content" />     </LinearLayout>     <LinearLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="horizontal">         <Button             android:id="@+id/clear"             android:layout_width="0dp"             android:layout_height="wrap_content"             android:layout_weight="1"             android:text="Clear"/>         <Button             android:id="@+id/dismiss"             android:layout_width="0dp"             android:layout_height="wrap_content"             android:layout_weight="1"             android:text="Dismiss"/>         <Button             android:id="@+id/enter"             android:layout_width="0dp"             android:layout_height="wrap_content"             android:layout_weight="1"             android:text="Enter"/>     </LinearLayout>  </LinearLayout> 

MainActivity.java
[remark: a põrnikas here, refer Update@2015-11-11on bottom of this post.]

package com.blogspot.android_er.androidbluetoothterminal;  import android.app.Activity; import android.app.Dialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.method.ScrollingMovementMethod; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast;  import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Set; import java.util.UUID;  populace class MainActivity extends AppCompatActivity {      someone static terminal int REQUEST_ENABLE_BT = 1;      BluetoothAdapter bluetoothAdapter;      ArrayList<BluetoothDevice> pairedDeviceArrayList;     ArrayAdapter<BluetoothDevice> pairedDeviceAdapter;     someone static UUID myUUID;     someone terminal String UUID_STRING_WELL_KNOWN_SPP =             "00001101-0000-1000-8000-00805F9B34FB";      ThreadConnectBTdevice myThreadConnectBTdevice;     ThreadConnected myThreadConnected;      static TextView body;     FloatingActionButton fab;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);         setSupportActionBar(toolbar);          torso = (TextView)findViewById(R.id.body);         body.setMovementMethod(new ScrollingMovementMethod());          fab = (FloatingActionButton) findViewById(R.id.fab);         fab.setOnClickListener(new View.OnClickListener() {             @Override             populace void onClick(View view) {                 showCmdLineDialog();             }         });          fab.setEnabled(false);         fab.setVisibility(FloatingActionButton.GONE);          if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){             Toast.makeText(this,                     "FEATURE_BLUETOOTH NOT support",                     Toast.LENGTH_LONG).show();             finish();             return;         }          //using the well-known SPP UUID         myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);          bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();         if (bluetoothAdapter == null) {             Toast.makeText(this,                     "Bluetooth is non supported on this hardware platform",                     Toast.LENGTH_LONG).show();             finish();             return;         }          String strInfo = bluetoothAdapter.getName() + "\n" +                 bluetoothAdapter.getAddress();         Toast.makeText(getApplicationContext(), strInfo, Toast.LENGTH_LONG).show();      }      @Override     protected void onStart() {         super.onStart();          //Turn ON BlueTooth if it is OFF         if (!bluetoothAdapter.isEnabled()) {             Intent enableIntent = novel Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);             startActivityForResult(enableIntent, REQUEST_ENABLE_BT);         }     }      @Override     protected void onDestroy() {         super.onDestroy();         closeThreads();     }      someone void closeThreads(){         if(myThreadConnectBTdevice!=null){             myThreadConnectBTdevice.cancel();             myThreadConnectBTdevice = null;         }          if(myThreadConnected!=null){             myThreadConnected.cancel();             myThreadConnected = null;         }     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         if(requestCode==REQUEST_ENABLE_BT){             if(resultCode == Activity.RESULT_OK){              }else{                 Toast.makeText(this,                         "BlueTooth NOT enabled",                         Toast.LENGTH_SHORT).show();                 finish();             }         }     }      @Override     populace boolean onCreateOptionsMenu(Menu menu) {         // Inflate the menu; this adds items to the activity bar if it is present.         getMenuInflater().inflate(R.menu.menu_main, menu);         supply true;     }      @Override     populace boolean onOptionsItemSelected(MenuItem item) {         // Handle activity bar special clicks here. The activity bar volition         // automatically handgrip clicks on the Home/Up button, in addition to thus long         // every bit y'all specify a bring upward activity inwards AndroidManifest.xml.         int id = item.getItemId();          //noinspection SimplifiableIfStatement         if (id == R.id.action_settings) {             closeThreads();             fab.setEnabled(false);             fab.setVisibility(FloatingActionButton.GONE);             body.setText("");             showSettingDialog();             supply true;         }          supply super.onOptionsItemSelected(item);     }      void showSettingDialog() {         FragmentTransaction ft = getFragmentManager().beginTransaction();         Fragment prev = getFragmentManager().findFragmentByTag("dialog");         if (prev != null) {             ft.remove(prev);         }         ft.addToBackStack(null);          DialogFragment newFragment = SettingDialogFragment.newInstance(MainActivity.this);         newFragment.show(ft, "dialog");      }      void showCmdLineDialog() {          if(myThreadConnected == null){             Toast.makeText(MainActivity.this,                     "myThreadConnected == null",                     Toast.LENGTH_LONG).show();             return;         }          FragmentTransaction ft = getFragmentManager().beginTransaction();         Fragment prev = getFragmentManager().findFragmentByTag("cmdline");         if (prev != null) {             ft.remove(prev);         }         ft.addToBackStack(null);          DialogFragment newFragment = TypingDialogFragment.newInstance(MainActivity.this, myThreadConnected);         newFragment.show(ft, "cmdline");      }      someone void setup(ListView lv, terminal Dialog dialog) {         Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();         if (pairedDevices.size() > 0) {             pairedDeviceArrayList = novel ArrayList<BluetoothDevice>();              for (BluetoothDevice device : pairedDevices) {                 pairedDeviceArrayList.add(device);             }              pairedDeviceAdapter = novel ArrayAdapter<BluetoothDevice>(this,                     android.R.layout.simple_list_item_1, pairedDeviceArrayList);             lv.setAdapter(pairedDeviceAdapter);              lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {                  @Override                 populace void onItemClick(AdapterView<?> parent, View view,                                         int position, long id) {                     BluetoothDevice device =                             (BluetoothDevice) parent.getItemAtPosition(position);                     Toast.makeText(MainActivity.this,                             "Name: " + device.getName() + "\n"                                     + "Address: " + device.getAddress() + "\n"                                     + "BondState: " + device.getBondState() + "\n"                                     + "BluetoothClass: " + device.getBluetoothClass() + "\n"                                     + "Class: " + device.getClass(),                             Toast.LENGTH_LONG).show();                      Toast.makeText(MainActivity.this, "start ThreadConnectBTdevice", Toast.LENGTH_LONG).show();                     myThreadConnectBTdevice = novel ThreadConnectBTdevice(device, dialog);                     myThreadConnectBTdevice.start();                 }             });         }     }      populace static class SettingDialogFragment extends DialogFragment {          ListView listViewPairedDevice;         static MainActivity parentActivity;          static SettingDialogFragment newInstance(MainActivity parent){             parentActivity = parent;             SettingDialogFragment f = novel SettingDialogFragment();             supply f;         }          @Nullable         @Override         populace View onCreateView(LayoutInflater inflater,                                  ViewGroup container, Bundle savedInstanceState) {             getDialog().setTitle("Setting");             getDialog().setCanceledOnTouchOutside(false);             View settingDialogView = inflater.inflate(R.layout.setting_layout, container, false);              listViewPairedDevice = (ListView)settingDialogView.findViewById(R.id.pairedlist);              parentActivity.setup(listViewPairedDevice, getDialog());              supply settingDialogView;         }     }      populace static class TypingDialogFragment extends DialogFragment {          EditText cmdLine;         static MainActivity parentActivity;         static ThreadConnected cmdThreadConnected;          static TypingDialogFragment newInstance(MainActivity parent, ThreadConnected thread){             parentActivity = parent;             cmdThreadConnected = thread;             TypingDialogFragment f = novel TypingDialogFragment();             supply f;         }          @Nullable         @Override         populace View onCreateView(LayoutInflater inflater,                                  ViewGroup container, Bundle savedInstanceState) {             getDialog().setTitle("Cmd Line");             getDialog().setCanceledOnTouchOutside(false);             View typingDialogView = inflater.inflate(R.layout.typing_layout, container, false);              cmdLine = (EditText)typingDialogView.findViewById(R.id.cmdline);              ImageView imgCleaarCmd = (ImageView)typingDialogView.findViewById(R.id.clearcmd);             imgCleaarCmd.setOnClickListener(new View.OnClickListener() {                 @Override                 populace void onClick(View v) {                     cmdLine.setText("");                 }             });              Button btnEnter = (Button)typingDialogView.findViewById(R.id.enter);             btnEnter.setOnClickListener(new View.OnClickListener() {                 @Override                 populace void onClick(View v) {                     if(cmdThreadConnected!=null){                         byte[] bytesToSend = cmdLine.getText().toString().getBytes();                         cmdThreadConnected.write(bytesToSend);                         byte[] NewLine = "\n".getBytes();                         cmdThreadConnected.write(NewLine);                     }                 }             });              Button btnDismiss = (Button)typingDialogView.findViewById(R.id.dismiss);             btnDismiss.setOnClickListener(new View.OnClickListener() {                 @Override                 populace void onClick(View v) {                     dismiss();                 }             });              Button btnClear = (Button)typingDialogView.findViewById(R.id.clear);             btnClear.setOnClickListener(new View.OnClickListener() {                 @Override                 populace void onClick(View v) {                     body.setText("");                 }             });              supply typingDialogView;         }     }      //Called inwards ThreadConnectBTdevice 1 time connect successed     //to root ThreadConnected     someone void startThreadConnected(BluetoothSocket socket){          myThreadConnected = novel ThreadConnected(socket);         myThreadConnected.start();     }      /*     ThreadConnectBTdevice:     Background Thread to handgrip BlueTooth connecting     */     someone class ThreadConnectBTdevice extends Thread {          someone BluetoothSocket bluetoothSocket = null;         someone terminal BluetoothDevice bluetoothDevice;         Dialog dialog;          someone ThreadConnectBTdevice(BluetoothDevice device, Dialog dialog) {             this.dialog = dialog;             bluetoothDevice = device;              create {                 bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);                 Toast.makeText(MainActivity.this,                         "bluetoothSocket: \n" + bluetoothSocket,                         Toast.LENGTH_SHORT).show();             } grab (IOException e) {                 // TODO Auto-generated grab block                 e.printStackTrace();             }         }          @Override         populace void run() {             boolean success = false;             create {                 bluetoothSocket.connect();                 success = true;             } grab (IOException e) {                 e.printStackTrace();                  terminal String eMessage = e.getMessage();                 runOnUiThread(new Runnable() {                      @Override                     populace void run() {                         Toast.makeText(MainActivity.this,                                 "something incorrect bluetoothSocket.connect(): \n" + eMessage,                                 Toast.LENGTH_SHORT).show();                     }                 });                  create {                     bluetoothSocket.close();                 } grab (IOException e1) {                     // TODO Auto-generated grab block                     e1.printStackTrace();                 }             }              if(success){                 //connect successful                 terminal String msgconnected = "connect successful:\n"                         + "BluetoothSocket: " + bluetoothSocket + "\n"                         + "BluetoothDevice: " + bluetoothDevice;                  runOnUiThread(new Runnable() {                      @Override                     populace void run() {                         fab.setEnabled(true);                         fab.setVisibility(FloatingActionButton.VISIBLE);                         body.setText("");                         Toast.makeText(MainActivity.this, msgconnected, Toast.LENGTH_LONG).show();                         dialog.dismiss();                     }                 });                  startThreadConnected(bluetoothSocket);              }else{                 //fail             }         }          populace void cancel() {              Toast.makeText(getApplicationContext(),                     "close bluetoothSocket",                     Toast.LENGTH_LONG).show();             create {                 bluetoothSocket.close();             } grab (IOException e) {                 // TODO Auto-generated grab block                 e.printStackTrace();             }          }      }      /*     ThreadConnected:     Background Thread to handgrip Bluetooth information communication     after connected      */     someone class ThreadConnected extends Thread {         someone terminal BluetoothSocket connectedBluetoothSocket;         someone terminal InputStream connectedInputStream;         someone terminal OutputStream connectedOutputStream;          boolean running;          populace ThreadConnected(BluetoothSocket socket) {             connectedBluetoothSocket = socket;             InputStream inwards = null;             OutputStream out = null;             running = true;             create {                 inwards = socket.getInputStream();                 out = socket.getOutputStream();             } grab (IOException e) {                 // TODO Auto-generated grab block                 e.printStackTrace();             }              connectedInputStream = in;             connectedOutputStream = out;         }          @Override         populace void run() {             byte[] buffer = novel byte[1024];             int bytes;              String strRx = "";              spell (running) {                 create {                     bytes = connectedInputStream.read(buffer);                     terminal String strReceived = novel String(buffer, 0, bytes);                     terminal String strByteCnt = String.valueOf(bytes) + " bytes received.\n";                      runOnUiThread(new Runnable(){                          @Override                         populace void run() {                             body.append(strReceived);                         }});                  } grab (IOException e) {                     // TODO Auto-generated grab block                     e.printStackTrace();                      terminal String msgConnectionLost = "Connection lost:\n"                             + e.getMessage();                     runOnUiThread(new Runnable(){                          @Override                         populace void run() {                             Toast.makeText(MainActivity.this, msgConnectionLost, Toast.LENGTH_LONG).show();                          }});                 }             }         }          populace void write(byte[] buffer) {             create {                 connectedOutputStream.write(buffer);             } grab (IOException e) {                 // TODO Auto-generated grab block                 e.printStackTrace();             }         }          populace void cancel() {             running = false;             create {                 connectedBluetoothSocket.close();             } grab (IOException e) {                 // TODO Auto-generated grab block                 e.printStackTrace();             }         }     }  }  

uses-permission of “android.permission.BLUETOOTH” is needed inwards src/main/AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="com.blogspot.android_er.androidbluetoothterminal" >      <uses-permission android:name="android.permission.BLUETOOTH"/>     <application         android:allowBackup="true"         android:icon="@mipmap/ic_launcher"         android:label="@string/app_name"         android:supportsRtl="true"         android:theme="@style/AppTheme" >         <activity             android:name=".MainActivity"             android:label="@string/app_name"             android:theme="@style/AppTheme.NoActionBar" >             <intent-filter>                 <action android:name="android.intent.action.MAIN" />                  <category android:name="android.intent.category.LAUNCHER" />             </intent-filter>         </activity>     </application>  </manifest>  

 The postal service inwards my about other blogspot demo how to  Android Bluetooth TerminalDownload the files (Android Studio Format) .

 The postal service inwards my about other blogspot demo how to  Android Bluetooth TerminalDownload APK .


Update@2015-11-11:
In the inwards a higher house code of MainActivity.java, inwards run() of ThreadConnected, if Connection lost (such every bit Raspberry Pi or HC-06 ability OFF), the thread volition even in addition to thus proceed running.

So accept to cancel the thread in addition to disable the FloatingActionButton. Modify run() of ThreadConnected.

        @Override         populace void run() {             byte[] buffer = novel byte[1024];             int bytes;              String strRx = "";              spell (running) {                 create {                     bytes = connectedInputStream.read(buffer);                     terminal String strReceived = novel String(buffer, 0, bytes);                     terminal String strByteCnt = String.valueOf(bytes) + " bytes received.\n";                      runOnUiThread(new Runnable(){                          @Override                         populace void run() {                             body.append(strReceived);                         }});                  } grab (IOException e) {                     // TODO Auto-generated grab block                     e.printStackTrace();                      cancel();                      terminal String msgConnectionLost = "Connection lost:\n"                             + e.getMessage();                     runOnUiThread(new Runnable(){                          @Override                         populace void run() {                             Toast.makeText(MainActivity.this, msgConnectionLost, Toast.LENGTH_LONG).show();                              fab.setEnabled(false);                             fab.setVisibility(FloatingActionButton.GONE);                          }});                 }             }         }