diff --git a/Android-Simple-Bluetooth-Example.zip b/Android-Simple-Bluetooth-Example.zip new file mode 100644 index 0000000..f5308c0 Binary files /dev/null and b/Android-Simple-Bluetooth-Example.zip differ diff --git a/app/build.gradle b/app/build.gradle index 56e822b..66310f6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdk 32 defaultConfig { applicationId "com.mcuhq.simplebluetooth" minSdkVersion 15 targetSdkVersion 23 - versionCode 1 + versionCode 29 versionName "1.0" } buildTypes { @@ -17,13 +16,19 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - lintOptions { - abortOnError false + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } + dependenciesInfo { + includeInApk true + includeInBundle true + } + buildToolsVersion '31.0.0 rc3' } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - testImplementation 'junit:junit:4.12' - implementation 'com.android.support:appcompat-v7:23.3.0' + testImplementation 'junit:junit:4.13.2' + implementation 'androidx.appcompat:appcompat:1.5.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b29f7e7..a1500ca 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,21 +4,27 @@ + + + + + - + diff --git a/app/src/main/java/com/mcuhq/simplebluetooth/MainActivity.java b/app/src/main/java/com/mcuhq/simplebluetooth/MainActivity.java index 17635b5..37756e6 100644 --- a/app/src/main/java/com/mcuhq/simplebluetooth/MainActivity.java +++ b/app/src/main/java/com/mcuhq/simplebluetooth/MainActivity.java @@ -13,9 +13,13 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +//import android.support.v4.app.ActivityCompat; +//import android.support.v4.content.ContextCompat; +//import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.AdapterView; @@ -29,6 +33,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.Set; import java.util.UUID; @@ -66,59 +71,55 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - mBluetoothStatus = (TextView)findViewById(R.id.bluetooth_status); + mBluetoothStatus = (TextView) findViewById(R.id.bluetooth_status); mReadBuffer = (TextView) findViewById(R.id.read_buffer); - mScanBtn = (Button)findViewById(R.id.scan); - mOffBtn = (Button)findViewById(R.id.off); - mDiscoverBtn = (Button)findViewById(R.id.discover); - mListPairedDevicesBtn = (Button)findViewById(R.id.paired_btn); - mLED1 = (CheckBox)findViewById(R.id.checkbox_led_1); + mScanBtn = (Button) findViewById(R.id.scan); + mOffBtn = (Button) findViewById(R.id.off); + mDiscoverBtn = (Button) findViewById(R.id.discover); + mListPairedDevicesBtn = (Button) findViewById(R.id.paired_btn); + mLED1 = (CheckBox) findViewById(R.id.checkbox_led_1); mBTArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1); mBTAdapter = BluetoothAdapter.getDefaultAdapter(); // get a handle on the bluetooth radio - mDevicesListView = (ListView)findViewById(R.id.devices_list_view); + mDevicesListView = (ListView) findViewById(R.id.devices_list_view); mDevicesListView.setAdapter(mBTArrayAdapter); // assign model to view mDevicesListView.setOnItemClickListener(mDeviceClickListener); // Ask for location permission if not already allowed - if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); - mHandler = new Handler(Looper.getMainLooper()){ + mHandler = new Handler(Looper.getMainLooper()) { @Override - public void handleMessage(Message msg){ - if(msg.what == MESSAGE_READ){ + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_READ) { String readMessage = null; - try { - readMessage = new String((byte[]) msg.obj, "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + readMessage = new String((byte[]) msg.obj, StandardCharsets.UTF_8); mReadBuffer.setText(readMessage); } - if(msg.what == CONNECTING_STATUS){ - if(msg.arg1 == 1) - mBluetoothStatus.setText("Connected to Device: " + msg.obj); + if (msg.what == CONNECTING_STATUS) { + char[] sConnected; + if (msg.arg1 == 1) + mBluetoothStatus.setText(getString(R.string.BTConnected) + msg.obj); else - mBluetoothStatus.setText("Connection Failed"); + mBluetoothStatus.setText(getString(R.string.BTconnFail)); } } }; if (mBTArrayAdapter == null) { // Device does not support Bluetooth - mBluetoothStatus.setText("Status: Bluetooth not found"); - Toast.makeText(getApplicationContext(),"Bluetooth device not found!",Toast.LENGTH_SHORT).show(); - } - else { + mBluetoothStatus.setText(getString(R.string.sBTstaNF)); + Toast.makeText(getApplicationContext(), getString(R.string.sBTdevNF), Toast.LENGTH_SHORT).show(); + } else { - mLED1.setOnClickListener(new View.OnClickListener(){ + mLED1.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v){ - if(mConnectedThread != null) //First check to make sure thread created + public void onClick(View v) { + if (mConnectedThread != null) //First check to make sure thread created mConnectedThread.write("1"); } }); @@ -131,79 +132,87 @@ public void onClick(View v) { } }); - mOffBtn.setOnClickListener(new View.OnClickListener(){ + mOffBtn.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v){ + public void onClick(View v) { bluetoothOff(); } }); mListPairedDevicesBtn.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v){ + public void onClick(View v) { listPairedDevices(); } }); - mDiscoverBtn.setOnClickListener(new View.OnClickListener(){ + mDiscoverBtn.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v){ + public void onClick(View v) { discover(); } }); } } - private void bluetoothOn(){ + private void bluetoothOn() { if (!mBTAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); - mBluetoothStatus.setText("Bluetooth enabled"); - Toast.makeText(getApplicationContext(),"Bluetooth turned on",Toast.LENGTH_SHORT).show(); + mBluetoothStatus.setText(getString(R.string.BTEnable)); + Toast.makeText(getApplicationContext(), getString(R.string.sBTturON), Toast.LENGTH_SHORT).show(); - } - else{ - Toast.makeText(getApplicationContext(),"Bluetooth is already on", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getApplicationContext(), getString(R.string.BTisON), Toast.LENGTH_SHORT).show(); } } // Enter here after user selects "yes" or "no" to enabling radio @Override - protected void onActivityResult(int requestCode, int resultCode, Intent Data){ + protected void onActivityResult(int requestCode, int resultCode, Intent Data) { // Check which request we're responding to if (requestCode == REQUEST_ENABLE_BT) { // Make sure the request was successful if (resultCode == RESULT_OK) { // The user picked a contact. // The Intent's data Uri identifies which contact was selected. - mBluetoothStatus.setText("Enabled"); - } - else - mBluetoothStatus.setText("Disabled"); + mBluetoothStatus.setText(getString(R.string.sEnabled)); + } else + mBluetoothStatus.setText(getString(R.string.sDisabled)); } } - private void bluetoothOff(){ + private void bluetoothOff() { mBTAdapter.disable(); // turn off - mBluetoothStatus.setText("Bluetooth disabled"); - Toast.makeText(getApplicationContext(),"Bluetooth turned Off", Toast.LENGTH_SHORT).show(); + mBluetoothStatus.setText(getString(R.string.sBTdisabl)); + Toast.makeText(getApplicationContext(), "Bluetooth turned Off", Toast.LENGTH_SHORT).show(); } - private void discover(){ + private void discover() { // Check if the device is already discovering - if(mBTAdapter.isDiscovering()){ - mBTAdapter.cancelDiscovery(); - Toast.makeText(getApplicationContext(),"Discovery stopped",Toast.LENGTH_SHORT).show(); + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + Toast.makeText(getBaseContext(), "Bluetooth Scan Permission denied", Toast.LENGTH_SHORT).show(); + return; } - else{ - if(mBTAdapter.isEnabled()) { + if (mBTAdapter.isDiscovering()) { + mBTAdapter.cancelDiscovery(); + + Toast.makeText(getApplicationContext(), getString(R.string.DisStop), Toast.LENGTH_SHORT).show(); + } else { + if (mBTAdapter.isEnabled()) { mBTArrayAdapter.clear(); // clear items mBTAdapter.startDiscovery(); - Toast.makeText(getApplicationContext(), "Discovery started", Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), getString(R.string.DisStart), Toast.LENGTH_SHORT).show(); registerReceiver(blReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND)); - } - else{ - Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getApplicationContext(), getString(R.string.BTnotOn), Toast.LENGTH_SHORT).show(); } } } @@ -212,47 +221,56 @@ private void discover(){ @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if(BluetoothDevice.ACTION_FOUND.equals(action)){ + if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // add the name to the list + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + Toast.makeText(getBaseContext(), "Socket Connection Permission denied", Toast.LENGTH_SHORT).show(); + return; + } mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress()); mBTArrayAdapter.notifyDataSetChanged(); } } }; - private void listPairedDevices(){ + private void listPairedDevices() { mBTArrayAdapter.clear(); mPairedDevices = mBTAdapter.getBondedDevices(); - if(mBTAdapter.isEnabled()) { + if (mBTAdapter.isEnabled()) { // put it's one to the adapter for (BluetoothDevice device : mPairedDevices) mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress()); - Toast.makeText(getApplicationContext(), "Show Paired Devices", Toast.LENGTH_SHORT).show(); - } - else - Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), getString(R.string.show_paired_devices), Toast.LENGTH_SHORT).show(); + } else + Toast.makeText(getApplicationContext(), getString(R.string.BTnotOn), Toast.LENGTH_SHORT).show(); } private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - if(!mBTAdapter.isEnabled()) { - Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show(); + if (!mBTAdapter.isEnabled()) { + Toast.makeText(getBaseContext(), getString(R.string.BTnotOn), Toast.LENGTH_SHORT).show(); return; } - mBluetoothStatus.setText("Connecting..."); + mBluetoothStatus.setText(getString(R.string.cConnet)); // Get the device MAC address, which is the last 17 chars in the View String info = ((TextView) view).getText().toString(); final String address = info.substring(info.length() - 17); - final String name = info.substring(0,info.length() - 17); + final String name = info.substring(0, info.length() - 17); // Spawn a new thread to avoid blocking the GUI one - new Thread() - { + new Thread() { @Override public void run() { boolean fail = false; @@ -263,10 +281,21 @@ public void run() { mBTSocket = createBluetoothSocket(device); } catch (IOException e) { fail = true; - Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show(); + Toast.makeText(getBaseContext(), getString(R.string.ErrSockCrea), Toast.LENGTH_SHORT).show(); } // Establish the Bluetooth socket connection. try { + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + Toast.makeText(getBaseContext(), "Socket creation Permission denied", Toast.LENGTH_SHORT).show(); + return; + } mBTSocket.connect(); } catch (IOException e) { try { @@ -276,10 +305,10 @@ public void run() { .sendToTarget(); } catch (IOException e2) { //insert code to deal with this - Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show(); + Toast.makeText(getBaseContext(), getString(R.string.ErrSockCrea), Toast.LENGTH_SHORT).show(); } } - if(!fail) { + if (!fail) { mConnectedThread = new ConnectedThread(mBTSocket, mHandler); mConnectedThread.start(); @@ -296,8 +325,18 @@ private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOE final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", UUID.class); return (BluetoothSocket) m.invoke(device, BT_MODULE_UUID); } catch (Exception e) { - Log.e(TAG, "Could not create Insecure RFComm Connection",e); + Log.e(TAG, "Could not create Insecure RFComm Connection", e); + } + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return null; } - return device.createRfcommSocketToServiceRecord(BT_MODULE_UUID); + return device.createRfcommSocketToServiceRecord(BT_MODULE_UUID); } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 545e63e..a8a86a1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -19,7 +19,7 @@ android:checked="false" android:scaleX="1.7" android:scaleY="1.7" - android:text="Toggle LED" + android:text="@string/toggle_led" android:textStyle="bold" /> + android:text="@string/lt_read_buffer" /> + android:text="@string/lt_bluetooth_status" />