Issue
I'm writing an app and it has a part which, on button click, scans for Bluetooth devices and shows them in a ListView. It works fine, but i need it to show only devices starting with a word in the name, for example: "MyArduino/123", so I need it to look for the "MyArduino/" part in device names and only show those that have it.
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.test.app.MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/title"
android:textSize="20sp"
android:textAlignment="center"
android:text="@string/title"
android:gravity="center_horizontal" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:text="@string/bt_menu"
android:background="@color/button"
android:onClick="showBt"
android:id="@+id/to_bt_menu"
android:layout_margin="10sp"
tools:ignore="UsingOnClickInXml" />
<Button
android:id="@+id/to_vars_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_marginLeft="10sp"
android:layout_marginStart="10sp"
android:layout_toEndOf="@id/to_bt_menu"
android:layout_toRightOf="@id/to_bt_menu"
android:onClick="showVars"
android:text="@string/vars_menu"
android:background="@color/button"
android:layout_margin="10sp"
tools:ignore="UsingOnClickInXml" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/to_bt_menu"
android:visibility="gone"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/status"
android:textStyle="bold" />
<TextView
android:id="@+id/bluetooth_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/to_bt_menu"
android:visibility="gone"
android:layout_toEndOf="@id/status"
android:layout_toRightOf="@id/status"
android:layout_marginLeft="20sp"
android:layout_marginStart="20sp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/bluetooth_status" />
<Button
android:id="@+id/scan"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_below="@id/bluetooth_status"
android:layout_margin="10sp"
android:visibility="gone"
android:text="@string/bluetooth_on"
android:background="@color/button" />
<Button
android:id="@+id/off"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_below="@id/bluetooth_status"
android:layout_margin="10sp"
android:visibility="gone"
android:layout_toRightOf="@id/scan"
android:layout_toEndOf="@id/scan"
android:background="@color/button"
android:text="@string/bluetooth_off" />
<Button
android:id="@+id/paired_btn"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_below="@id/off"
android:layout_margin="10sp"
android:visibility="gone"
android:text="@string/show_paired_devices"
android:background="@color/button" />
<Button
android:id="@+id/discover"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_below="@id/off"
android:layout_margin="10sp"
android:visibility="gone"
android:layout_toEndOf="@+id/paired_btn"
android:layout_toRightOf="@id/paired_btn"
android:text="@string/discover_new_devices"
android:background="@color/button" />
<ListView
android:id="@+id/devices_list_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/discover"
android:visibility="gone"
android:choiceMode="singleChoice" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20sp"
android:onClick="reqVars"
android:text="@string/req_btn"
android:layout_below="@id/user_edit"
android:visibility="gone"
android:id="@+id/req_btn"
android:layout_margin="10sp"
android:background="@color/button" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/to_vars_menu"
android:layout_margin="10sp"
android:visibility="gone"
android:id="@+id/user_edit"
android:hint="@string/hint_edit"
tools:ignore="TextFields"/>
<Button
android:id="@+id/send_edit_btn"
android:layout_margin="10sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/user_edit"
android:visibility="gone"
android:layout_marginStart="20sp"
android:layout_marginLeft="20sp"
android:layout_marginTop="20sp"
android:layout_toEndOf="@+id/req_btn"
android:layout_toRightOf="@+id/req_btn"
android:onClick="editVar"
android:text="@string/send_edit_btn"
android:background="@color/button" />
<ListView
android:layout_below="@id/req_btn"
android:visibility="gone"
android:id="@+id/vars"
android:choiceMode="singleChoice"
android:listSelector="@color/list"
android:layout_width="300sp"
android:layout_height="wrap_content" />
</RelativeLayout>
MainActivity:
package com.test.app;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
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;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private final String TAG = MainActivity.class.getSimpleName();
private static final UUID BT_MODULE_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // "random" unique identifier
// #defines for identifying shared types between calling functions
private final static int REQUEST_ENABLE_BT = 1; // used to identify adding bluetooth names
public final static int MESSAGE_READ = 2; // used in bluetooth handler to identify message update
private final static int CONNECTING_STATUS = 3; // used in bluetooth handler to identify message status
// GUI Components
private TextView mBluetoothStatus;
private Button mScanBtn;
private Button mOffBtn;
private Button mListPairedDevicesBtn;
private Button mDiscoverBtn;
private ListView mDevicesListView;
private TextView mStatus;
private EditText mUserEdit;
private Button mReqBtn;
private Button mSendEdit;
private ListView mVars;
private String mSelecVar;
private String mMessage;
private BluetoothAdapter mBTAdapter;
private Set<BluetoothDevice> mPairedDevices;
private ArrayList<BluetoothDevice> mBTDevices;
private ArrayAdapter<String> mBTArrayAdapter;
private Handler mHandler; // Our main handler that will receive callback notifications
private ConnectedThread mConnectedThread; // bluetooth background worker thread to send and receive data
private BluetoothSocket mBTSocket = null; // bi-directional client-to-client data path
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Objects.requireNonNull(getSupportActionBar()).hide();
} else {
getSupportActionBar().hide();
}
setContentView(R.layout.activity_main);
mBluetoothStatus = (TextView)findViewById(R.id.bluetooth_status);
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);
mStatus = (TextView)findViewById(R.id.status);
mUserEdit = (EditText)findViewById(R.id.user_edit);
mReqBtn = (Button)findViewById(R.id.req_btn);
mSendEdit = (Button)findViewById(R.id.send_edit_btn);
mVars = (ListView)findViewById(R.id.vars);
mBTArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
mBTDevices = new ArrayList<>();
mBTAdapter = BluetoothAdapter.getDefaultAdapter(); // get a handle on the bluetooth radio
mDevicesListView = (ListView)findViewById(R.id.devices_list_view);
assert mDevicesListView != null;
mDevicesListView.setAdapter(mBTArrayAdapter); // assign model to view
mDevicesListView.setOnItemClickListener(mDeviceClickListener);
mVars.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mSelecVar = mVars.getItemAtPosition(position).toString().split(",")[0];
}
});
// Ask for location permission if not already allowed
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()){
@Override
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();
}
mMessage = readMessage;
if (mMessage != null) {
for (int i = 0; i < mMessage.length(); i++) {
if (mMessage.toCharArray()[i] == ';') {
getVars(mMessage);
break;
}
}
}
}
if(msg.what == CONNECTING_STATUS){
if(msg.arg1 == 1) {
mBluetoothStatus.setText("Connected to Device: " + msg.obj);
mConnectedThread.write("list");
} else
mBluetoothStatus.setText("Connection Failed");
}
}
};
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 {
mScanBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bluetoothOn();
}
});
mOffBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
bluetoothOff();
}
});
mListPairedDevicesBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
listPairedDevices();
}
});
mDiscoverBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
discover();
}
});
}
}
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();
}
else{
Toast.makeText(getApplicationContext(),"Bluetooth is already on", 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){
// 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");
}
}
private void bluetoothOff(){
mBTAdapter.disable(); // turn off
mBluetoothStatus.setText("Bluetooth disabled");
Toast.makeText(getApplicationContext(),"Bluetooth turned Off", Toast.LENGTH_SHORT).show();
}
private void discover(){
// Check if the device is already discovering
if(mBTAdapter.isDiscovering()){
mBTAdapter.cancelDiscovery();
Toast.makeText(getApplicationContext(),"Discovery stopped",Toast.LENGTH_SHORT).show();
}
else{
if(mBTAdapter.isEnabled()) {
mBTArrayAdapter.clear(); // clear items
mBTAdapter.startDiscovery();
Toast.makeText(getApplicationContext(), "Discovery started", Toast.LENGTH_SHORT).show();
registerReceiver(blReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
else{
Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
}
}
}
final BroadcastReceiver blReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// add the name to the list
mBTDevices.add(device);
mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress());
mBTArrayAdapter.notifyDataSetChanged();
}
if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
BluetoothDevice mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDED){
Log.d(TAG, "BroadcastReceiver: BOND_BONDED");
}
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDING){
Log.d(TAG, "BroadcastReceiver: BOND_BONDING");
}
if (mDevice.getBondState() == BluetoothDevice.BOND_NONE){
Log.d(TAG, "BroadcastReceiver: BOND_NONE");
}
}
}
};
private void listPairedDevices(){
mBTArrayAdapter.clear();
mPairedDevices = mBTAdapter.getBondedDevices();
if(mBTAdapter.isEnabled()) {
// put it's one to the adapter
for (BluetoothDevice device : mPairedDevices)
if (device.getName().equals("MyArduino/")){
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();
}
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();
return;
}
mBluetoothStatus.setText("Connecting...");
// 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);
// Spawn a new thread to avoid blocking the GUI one
new Thread()
{
@Override
public void run() {
boolean fail = false;
BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
try {
mBTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
mBTSocket.connect();
} catch (IOException e) {
try {
fail = true;
mBTSocket.close();
mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if(!fail) {
mConnectedThread = new ConnectedThread(mBTSocket, mHandler);
mConnectedThread.start();
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
};
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
try {
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);
}
return device.createRfcommSocketToServiceRecord(BT_MODULE_UUID);
}
public void showBt(View view) {
mBluetoothStatus.setVisibility(View.VISIBLE);
mScanBtn.setVisibility(View.VISIBLE);
mOffBtn.setVisibility(View.VISIBLE);
mDiscoverBtn.setVisibility(View.VISIBLE);
mListPairedDevicesBtn.setVisibility(View.VISIBLE);
mDevicesListView.setVisibility(View.VISIBLE);
mStatus.setVisibility(View.VISIBLE);
mVars.setVisibility(View.GONE);
mUserEdit.setVisibility(View.GONE);
mSendEdit.setVisibility(View.GONE);
mReqBtn.setVisibility(View.GONE);
}
public void showVars(View view) {
mBluetoothStatus.setVisibility(View.GONE);
mScanBtn.setVisibility(View.GONE);
mOffBtn.setVisibility(View.GONE);
mDiscoverBtn.setVisibility(View.GONE);
mListPairedDevicesBtn.setVisibility(View.GONE);
mDevicesListView.setVisibility(View.GONE);
mStatus.setVisibility(View.GONE);
mVars.setVisibility(View.VISIBLE);
mUserEdit.setVisibility(View.VISIBLE);
mSendEdit.setVisibility(View.VISIBLE);
mReqBtn.setVisibility(View.VISIBLE);
}
public void reqVars(View view) {
if (mConnectedThread != null){
mConnectedThread.write("list");
}
}
public void getVars(String string) {
String[] str = string.split(";");
List<String> al;
al = Arrays.asList(str);
ArrayAdapter<String> mVarsArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, al);
mVars.setAdapter(mVarsArrayAdapter);
}
public void editVar(View view) {
if (mConnectedThread != null) {
mConnectedThread.write("edit " + mSelecVar + " " + mUserEdit.getText());
mUserEdit.setText("");
SystemClock.sleep(2000);
mConnectedThread.write("list");
}
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
mBTAdapter.cancelDiscovery();
Log.d(TAG, "onItemClick: You clicked on a device.");
String deviceName = mBTDevices.get(i).getName();
String deviceAddress = mBTDevices.get(i).getAddress();
Log.d(TAG, "onItemClick: deviceName = " + deviceName);
Log.d(TAG, "onItemClick: deviceAddress = " + deviceAddress);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2){
Log.d(TAG, "Trying to pair with " + deviceName);
mBTDevices.get(i).createBond();
}
}
}
ConnectedThread:
package com.test.app;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.SystemClock;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private final Handler mHandler;
public ConnectedThread(BluetoothSocket socket, Handler handler) {
mmSocket = socket;
mHandler = handler;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.available();
if(bytes != 0) {
buffer = new byte[1024];
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String input) {
byte[] bytes = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
Right now, the ListView shows all the devices that the Bluetooth founds, and sometimes, even shows them 2 or 3 times in the same list. As you can see in the MainActivity, i tried to make some sort of a filter in line 272 but it just does not work. Thanks
Solution
So, after hours of trial and error, the problem was solved.
I've noticed this line in the errors on crash:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference
It means that the function was looking for "MyArduino/" in a null object. So i modified this:
if(device.getName().startsWith("MyArduino/")){
mBTDevices.add(device);
mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress());
mBTArrayAdapter.notifyDataSetChanged();
}
To this:
if (device.getName() != null) {
if (device.getName().contains("MyAdruino/")) {
mBTArrayAdapter.add(device.getName() + "\n" + device.getAddress());
mBTArrayAdapter.notifyDataSetChanged();
}
}
And the problem was solved. It just showed the devices with "MyAdruino/" names and only once. Hope this will help anyone that gets the same problem
Answered By - sdw2302
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.