-3

I am trying to Send a Bluetooth Device Discovered in an activity to another class to Perform Further Functionality......while trying to do so with the Help of a Constructor I am getting nullPointerException for the Bluetooth Device.

below is the code for ScanActivity wherein, the BroadcastReceiver is used to Discover the nearby Bluetooth devices, after receiving the device, the name and address are initialized to the device model class and then sent to the recyclerViewAdapter(Bluetooth_adapter) to set it in the View Holder.

public class ScanActivity extends AppCompatActivity {
    private static final String TAG = "ScanActivity";
    private static final int REQUEST_BT_ENABLE = 1;
    private static final int disrequestCode = 5;
    RecyclerView recyclerViewSD;
    BluetoothAdapter bluetoothAdapter;
    ArrayList<BluetoothDeviceModel> data;
    SnackBarShowing snackBarShowing;
    Bluetooth_adapter Adapter;
    LinearProgressIndicator linearProgressIndicator;
    View rootView;
    BluetoothClass bluetoothClass;
    private CircularProgressIndicator indicator;
    AsignLogo asignLogo;
    private ImageView reloadButton;

    private Handler handler = new Handler();

    private IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);



    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @RequiresApi(api = Build.VERSION_CODES.S)
        @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);
                if (ActivityCompat.checkSelfPermission(ScanActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestPermissions(new String[]{Manifest.permission.BLUETOOTH_CONNECT}, 1);
                }

                String deviceName = device.getName();
                String deviceAddress = device.getAddress();
                linearProgressIndicator.setVisibility(View.GONE);

                //-------for logo---------
                bluetoothClass = device.getBluetoothClass();
                asignLogo = new AsignLogo(bluetoothClass);
                int logoResourse = asignLogo.getDeviceLogoResource(bluetoothClass);
                //------------------------

                data.add(new BluetoothDeviceModel(deviceName, deviceAddress, logoResourse));
                Adapter = new Bluetooth_adapter(data, getApplicationContext());
                recyclerViewSD.setAdapter(Adapter);

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        indicator.setVisibility(View.GONE);
                        reloadButton.setVisibility(View.VISIBLE);
                    }
                }, 4000);

            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: Starts");
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_scan);

        recyclerViewSD = (RecyclerView) findViewById(R.id.Scan_devices_RV);
        recyclerViewSD.setLayoutManager(new LinearLayoutManager(this));

        snackBarShowing = new SnackBarShowing();
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        data = new ArrayList<BluetoothDeviceModel>();
        linearProgressIndicator = (LinearProgressIndicator) findViewById(R.id.progress_indicator);
        rootView = this.getWindow().getDecorView().findViewById(android.R.id.content);
        indicator = (CircularProgressIndicator) findViewById(R.id.CPI);
        reloadButton = (ImageView) findViewById(R.id.reload_btn);
        reloadButton.setVisibility(View.GONE);


        if (bluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not supported on this device", Toast.LENGTH_SHORT).show();
            finish();
        }

        // Request necessary permissions if not granted already
        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        }

        startDiscovery();

        reloadButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                reload();
            }
        });
    }

    private void reload(){
        cancelDiscovery();
        unregisterReceiver(receiver);
        data.clear();
        startDiscovery();
        registerReceiver(receiver, filter);
        reloadButton.setVisibility(View.GONE);
        new Handler().postAtTime(new Runnable() {
            @Override
            public void run() {
                indicator.setVisibility(View.VISIBLE);
            }
        }, 3000);
    }

    private void establishConnection(){

    }

    private void startDiscovery() {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.BLUETOOTH_SCAN}, 1);
        } else {
            bluetoothAdapter.startDiscovery();
            Toast.makeText(this, "Scanning for devices...", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "startDiscovery: Discovery: " + bluetoothAdapter.startDiscovery());
        }
    }


    private void cancelDiscovery() {
        if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
            Log.d(TAG, "cancelDiscovery: Discovery Cancelled");
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.S)
    void enableDiscover() {
        Intent discoverableIntent =
                new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 180);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.BLUETOOTH_ADVERTISE} , disrequestCode);
        }
        startActivityForResult(discoverableIntent, disrequestCode);
    }


    public void checkBluetooth() {
        if (!bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            } else {
                startActivityForResult(intent, REQUEST_BT_ENABLE);
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG, "onActivityResult: Request Code: " + requestCode);
        if (requestCode == REQUEST_BT_ENABLE && requestCode == disrequestCode) {
            Log.d(TAG, "onActivityResult: REQcode: " + requestCode);
            if (resultCode == RESULT_OK) {
                Log.d(TAG, "onActivityResult: ResultCode: " + resultCode);
                Toast.makeText(this, "Done", Toast.LENGTH_SHORT).show();
            } else {
                Log.d(TAG, "onActivityResult: Result Code : " + resultCode);
                Log.d(TAG, "onActivityResult: ResultOK: " + RESULT_OK);
                snackBarShowing.showSnackbar(rootView, "Bluetooth needs to be Enabled", Snackbar.LENGTH_SHORT, "enable", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        checkBluetooth();
                    }
                });
            }
        }
    }



    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
        cancelDiscovery();
    }

    @Override
    protected void onStart() {
        super.onStart();
        checkBluetooth();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            int discoverableMode = bluetoothAdapter.getScanMode();
            Log.d(TAG, "onStart: DiscoverableMode: " + discoverableMode);
            Log.d(TAG, "onStart: Scan mode Connectable_Discoverable: " + BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
            Log.d(TAG, "onStart: Scan mode Connectable: " + BluetoothAdapter.SCAN_MODE_CONNECTABLE );
            if (discoverableMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE || discoverableMode ==BluetoothAdapter.SCAN_MODE_CONNECTABLE){
                return;
            }else{
                enableDiscover();
            }
        }
    }
}

How to pass the Bluetooth Device discovered in ScanActivity to the adapter class below.

public class Bluetooth_adapter extends RecyclerView.Adapter<BluetoothViewHolder> {

    BluetoothDevice selectedDevice;
    ArrayList<BluetoothDeviceModel> data;
    Context context;

    AsignLogo asignLogo;
    AdapterType adapterType;

    private clickListener clickListener;
    private List<BluetoothDevice> devices;



    public Bluetooth_adapter(AdapterType adapterType) {
        this.adapterType = adapterType;
    }

    public Bluetooth_adapter(List<BluetoothDevice> devices, clickListener clickListener) {
        this.devices = devices;
        this.clickListener = clickListener;

    }
    public Bluetooth_adapter(ArrayList<BluetoothDeviceModel> data, Context context) {
        this.data = data;
        this.context = context;
    }

    @NonNull
    @Override
    public BluetoothViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // This will create a blank box of Defined XMl File
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view1 = inflater.inflate(R.layout.pair_devices, parent, false);
        View view2 = inflater.inflate(R.layout.devices, parent, false);
        // In the fields we are passing the views from the View Holder.
        return new BluetoothViewHolder(view1);

    }

    @Override
    public void onBindViewHolder(@NonNull BluetoothViewHolder holder, int position) {
        BluetoothDeviceModel deviceModel = data.get(position);
        //BluetoothDevice device = devices.get(position);

        Log.d(TAG, "onBindViewHolder: Adapter List: " + devices);

        String name = data.get(position).getName();
        String address = data.get(position).getAddress();
        int imgresource = data.get(position).getImageresouce();

        holder.dropdownImgPD.setImageResource(imgresource);

        if (name == null) {
            holder.deviceNamePD.setText(address);
        } else {
            holder.deviceNamePD.setText(name);
        }

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               //clickListener.on_Click_Listener(device);
            }
        };

        holder.cardViewPD.setOnClickListener(listener);

    }
    @Override
    public int getItemCount() {
        return data.size();
    }
}
  • You say *sending device to another activity* but you try to set a recyclerview adapter. An adapter is not an activity. Where is your another activity then? In what line are you getting null exactly? Consider adding the error message if any. – Kozmotronik Jul 01 '23 at 09:02
  • From what I've seen, you create new adapter for each new found device. This is a bad practice. Consider using either [notifyDataSetChanged](https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter#notifyDataSetChanged()) to force the recyclerview to recreate all its items (not a preferred way), or [notifyItemInserted](https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter#notifyItemInserted(int)) for each device found. The latter is the prefferred way for better performance. – Kozmotronik Jul 01 '23 at 09:10
  • @Kozmotronik I want to get the Device which was clicked in the recycler View And Send That Device to Another Class (sry for the confusion) for Connection and further Functionality , so how can I Establish a Callback to do So. also Sending the device to Adapter using Constructor is Showing null on that reference Variable , been stuck on this from many Days – joash deoghare Jul 03 '23 at 07:05
  • I see, however your question is not clear enough. Passing data/object between 2 activities and passing data/object from an activity to a recyclerview adapter is not the same. These two cases are handled differently. Now what I understand from your last comment, you can't event pass the found bluetooth object to your adapter class ( you get null) so that you can proceed further and pass a selected device data to another activity for further functionality. Hopefully I get it correct. – Kozmotronik Jul 03 '23 at 09:13
  • yes that's correct, I just want Help on how to send a Bluetooth Device Discovered in an Activity to another Class for further Functionality – joash deoghare Jul 03 '23 at 12:27
  • I will try to help you with a working example as soon as I can so that you can achieve your goal, keep watching. – Kozmotronik Jul 04 '23 at 10:51
  • In the meantime, I recommend you to edit your question and make it as clear as possible so that the readers can understand your goal without confusion. Otherwise some users can downvote your question because of unclarity and consequently your question would get closed. – Kozmotronik Jul 04 '23 at 10:59
  • Thanks. Edited it now, I hope it addresses the issue more clearly now. – joash deoghare Jul 05 '23 at 04:56

1 Answers1

0

I'm late a little in answering due to my occupation. But hopefully with the help of my answer you achieve to add your found bluetooth device to the list and then process it further. We will start by spotting some bad practices in your code and then fix them.

The first bad practice I see is that you create a new adapter and set it to the recylerview everytime a new device found in your receiver implementation of ScanActivity class.

ScanActivity.java

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @RequiresApi(api = Build.VERSION_CODES.S)
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            ...
            data.add(new BluetoothDeviceModel(deviceName, deviceAddress, logoResourse));
            Adapter = new Bluetooth_adapter(data, getApplicationContext());
            recyclerViewSD.setAdapter(Adapter);
            ...
        }
    }
};

This is not a good practice since you keep creating a new adapter and passing the same data. Instead, you should create the adapter and set it to the recyclerview once in the ScanActivity's life cycle to avoid unnecessary repeated operations. Here is how it would look like in the fixed code:

ScanActivity.java

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @RequiresApi(api = Build.VERSION_CODES.S)
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            ...
            // Post it to the main thread since it will touch the view objects
            handler.post(() -> {
                scanListAdapter.addDevice(new BluetoothDeviceModel(deviceName, deviceAddress, logoResourse));
            });
            ...
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    recyclerViewSD = (RecyclerView) findViewById(R.id.Scan_devices_RV);
    recyclerViewSD.setLayoutManager(new LinearLayoutManager(this));

    // Set the recyclerview adapter only once here
    final DeviceSelectListener deviceSelectListener = new DeviceSelectListener {
        @Override
        void onDeviceSelected(BluetoothDeviceModel deviceModel) {
            // A device selected from the list, send the selected device information
            // to another activity for further operations.
            // TODO handle the selected device
        }
    }
    scanListAdapter = new BLEScanListAdapter(deviceSelectListener);
    recyclerViewSD.setAdapter(scanListAdapter);
    ...
}

You will see the whole code later on.

Another bad practice is how you name the recyclerview adapter. Naming your classes very similar to the Android APIs name can create confusions. Make sure you name your classes, interfaces and variables in a such way that more or less they reflect what they are defined for and their purposes. So I made name changes as followings:

  • Bluetooth_adapter to BluetoothScanListAdapter
  • clickListener to DeviceSelectListener

Since you haven't shared the clickListener implementation I've added its modified implementation to the scan list adapter. In this modified implementation, we pass the selected device to the listener target so that the listener can process on it.

BluetoothScanListAdapter.java

static interface DeviceSelectListener {
    void onDeviceSelected(BluetoothDeviceModel deviceModel);
}

Another change I've made is to optimize your BluetoothScanListAdapter's construction and data organization between the ScanActivity and the adapter class. I left the management of the data set to the BluetoothScanListAdapter to avoid confusions. So the device list named data is removed from ScanActivity since it is not needed anymore. Here is how the consructor looks like:

BluetoothScanListAdapter.java

ArrayList<BluetoothDeviceModel> data;
private DeviceSelectListener selectListener;
private List<BluetoothDeviceModel> devices;


public BluetoothScanListAdapter(DeviceSelectListener selectListener) {
    this.devices = new ArrayList<>(); // Initialize an empty list
    this.selectListener = selectListener;
}

Then I modified the OnClickListener implementation of the view holder in the onBindViewHolder callback to propagate the device selection that detected in the BluetoothScanListAdapter clas to its listener. The modification includes precaution checks against any possible invalid data:

BluetoothScanListAdapter.java

@Override
public void onBindViewHolder(@NonNull BluetoothViewHolder holder, int position) {
    BluetoothDeviceModel deviceModel = data.get(position);
    ...
    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // Don't rely on the position parameter since it can be changed when scrolling screen
            final index = holder.getAbsoluteAdapterPosition();
            // Bound check
            if (index < 0 || index >= devices.size()) {
                Log.d("Adapter: A selection has made but couldn't get a valid index");
                return;
            }
            final BluetoothDeviceModel deviceModel = devices.get(index);
            // ArrayLists can store null objects, check it is not null
            if (deviceModel == null) {
                Log.d("Adapter: Selected device is null. Index is "+index);
                return;
            }
            // Finally we can propagate the selected device safely
            if (selectListener != null) selectListener.onDeviceSelected(deviceModel);
        }
    };
    holder.cardViewPD.setOnClickListener(listener);
}

The next needed change has been made in the ScanActivity's onCreate method in order to listen to the device selection event so that the ScanActivity responds when a device is selected from the list.

ScanActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Set the recyclerview adapter only once here
    final DeviceSelectListener deviceSelectListener = new DeviceSelectListener {
        @Override
        void onDeviceSelected(BluetoothDeviceModel deviceModel) {
            // A device selected from the list, send the selected device information
            // to another activity for further operations.
            // TODO handle the selected device
            Log.d("ScanActivity: Selected device adress "+deviceModel.getAddress());
        }
    }
    scanListAdapter = new BluetoothScanListAdapter(deviceSelectListener);
    recyclerViewSD.setAdapter(scanListAdapter);
    ...
}

The final step is where I marked with TODO, to handle the selected device for further operations. But since I don't know what activity will be the one to handle those further operations, I leave it to you. You can pass data using some different ways between activities. There are plenty of great examples in this post on how to do it.

Although it is out of scope of the actual problem, there is one more bad practice in the BroadcastReceiver definition that I'd like to point out:

ScanActivity.java

private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @RequiresApi(api = Build.VERSION_CODES.S)
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                ...
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        indicator.setVisibility(View.GONE);
                        reloadButton.setVisibility(View.VISIBLE);
                    }
                }, 4000);
            }
        }
    };

This is bad because a runnable with a delay will be posted to the main queue whenever a device found by the bluetooth scanner. Imagine where you surrounded with many devices that are advertising. You need to figure out a way to not to post that runnable whenever a device found.

Well I think that's it. I will leave the modified classes below so that you can connect the dots. I made this modification in a text editor. So it is not tested. But the general logic should work. It is up to you to test the code and give a feedback whether it worked or not.

ScanActivity.java

public class ScanActivity extends AppCompatActivity {
    private static final String TAG = "ScanActivity";
    private static final int REQUEST_BT_ENABLE = 1;
    private static final int disrequestCode = 5;
    RecyclerView recyclerViewSD;
    BluetoothAdapter bluetoothAdapter;
    SnackBarShowing snackBarShowing;
    BluetoothScanListAdapter scanListAdapter;
    LinearProgressIndicator linearProgressIndicator;
    View rootView;
    BluetoothClass bluetoothClass;
    private CircularProgressIndicator indicator;
    AsignLogo asignLogo;
    private ImageView reloadButton;

    private Handler handler = new Handler();

    private IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);



    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @RequiresApi(api = Build.VERSION_CODES.S)
        @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);
                if (ActivityCompat.checkSelfPermission(ScanActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestPermissions(new String[]{Manifest.permission.BLUETOOTH_CONNECT}, 1);
                }

                String deviceName = device.getName();
                String deviceAddress = device.getAddress();
                linearProgressIndicator.setVisibility(View.GONE);

                //-------for logo---------
                bluetoothClass = device.getBluetoothClass();
                asignLogo = new AsignLogo(bluetoothClass);
                int logoResourse = asignLogo.getDeviceLogoResource(bluetoothClass);
                //------------------------

                // Post it to the main thread since it will touch the view objects
                handler.post(() -> {
                    scanListAdapter.addDevice(new BluetoothDeviceModel(deviceName, deviceAddress, logoResourse));
                });

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        indicator.setVisibility(View.GONE);
                        reloadButton.setVisibility(View.VISIBLE);
                    }
                }, 4000);

            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: Starts");
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_scan);

        recyclerViewSD = (RecyclerView) findViewById(R.id.Scan_devices_RV);
        recyclerViewSD.setLayoutManager(new LinearLayoutManager(this));

        // Set the recyclerview adapter only once here
        final DeviceSelectListener deviceSelectListener = new DeviceSelectListener {
            @Override
            void onDeviceSelected(BluetoothDeviceModel deviceModel) {
                // A device selected from the list, send the selected device information
                // to another activity for further operations.
                // TODO handle the selected device
                Log.d("ScanActivity: Selected device adress "+deviceModel.getAddress());
            }
        }
        scanListAdapter = new BluetoothScanListAdapter(deviceSelectListener);
        recyclerViewSD.setAdapter(scanListAdapter);

        snackBarShowing = new SnackBarShowing();
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        data = new ArrayList<BluetoothDeviceModel>();
        linearProgressIndicator = (LinearProgressIndicator) findViewById(R.id.progress_indicator);
        rootView = this.getWindow().getDecorView().findViewById(android.R.id.content);
        indicator = (CircularProgressIndicator) findViewById(R.id.CPI);
        reloadButton = (ImageView) findViewById(R.id.reload_btn);
        reloadButton.setVisibility(View.GONE);


        if (bluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not supported on this device", Toast.LENGTH_SHORT).show();
            finish();
        }

        // Request necessary permissions if not granted already
        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        }

        startDiscovery();

        reloadButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                reload();
            }
        });
    }

    private void reload(){
        cancelDiscovery();
        unregisterReceiver(receiver);
        data.clear();
        startDiscovery();
        registerReceiver(receiver, filter);
        reloadButton.setVisibility(View.GONE);
        new Handler().postAtTime(new Runnable() {
            @Override
            public void run() {
                indicator.setVisibility(View.VISIBLE);
            }
        }, 3000);
    }

    private void establishConnection(){

    }

    private void startDiscovery() {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.BLUETOOTH_SCAN}, 1);
        } else {
            bluetoothAdapter.startDiscovery();
            Toast.makeText(this, "Scanning for devices...", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "startDiscovery: Discovery: " + bluetoothAdapter.startDiscovery());
        }
    }


    private void cancelDiscovery() {
        if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
            Log.d(TAG, "cancelDiscovery: Discovery Cancelled");
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.S)
    void enableDiscover() {
        Intent discoverableIntent =
                new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 180);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.BLUETOOTH_ADVERTISE} , disrequestCode);
        }
        startActivityForResult(discoverableIntent, disrequestCode);
    }


    public void checkBluetooth() {
        if (!bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            } else {
                startActivityForResult(intent, REQUEST_BT_ENABLE);
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG, "onActivityResult: Request Code: " + requestCode);
        if (requestCode == REQUEST_BT_ENABLE && requestCode == disrequestCode) {
            Log.d(TAG, "onActivityResult: REQcode: " + requestCode);
            if (resultCode == RESULT_OK) {
                Log.d(TAG, "onActivityResult: ResultCode: " + resultCode);
                Toast.makeText(this, "Done", Toast.LENGTH_SHORT).show();
            } else {
                Log.d(TAG, "onActivityResult: Result Code : " + resultCode);
                Log.d(TAG, "onActivityResult: ResultOK: " + RESULT_OK);
                snackBarShowing.showSnackbar(rootView, "Bluetooth needs to be Enabled", Snackbar.LENGTH_SHORT, "enable", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        checkBluetooth();
                    }
                });
            }
        }
    }



    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
        cancelDiscovery();
    }

    @Override
    protected void onStart() {
        super.onStart();
        checkBluetooth();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            int discoverableMode = bluetoothAdapter.getScanMode();
            Log.d(TAG, "onStart: DiscoverableMode: " + discoverableMode);
            Log.d(TAG, "onStart: Scan mode Connectable_Discoverable: " + BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
            Log.d(TAG, "onStart: Scan mode Connectable: " + BluetoothAdapter.SCAN_MODE_CONNECTABLE );
            if (discoverableMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE || discoverableMode ==BluetoothAdapter.SCAN_MODE_CONNECTABLE){
                return;
            }else{
                enableDiscover();
            }
        }
    }
}

BluetoothScanListAdapter.java

public class BluetoothScanListAdapter extends RecyclerView.Adapter<BluetoothViewHolder> {

    static interface DeviceSelectListener {
        void onDeviceSelected(BluetoothDeviceModel deviceModel);
    }

    ArrayList<BluetoothDeviceModel> data;
    private DeviceSelectListener selectListener;
    private List<BluetoothDeviceModel> devices;


    public BluetoothScanListAdapter(DeviceSelectListener selectListener) {
        this.devices = new ArrayList<>(); // Initialize an empty list
        this.selectListener = selectListener;
    }

    @NonNull
    @Override
    public BluetoothViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // This will create a blank box of Defined XMl File
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view1 = inflater.inflate(R.layout.pair_devices, parent, false);
        View view2 = inflater.inflate(R.layout.devices, parent, false);
        // In the fields we are passing the views from the View Holder.
        return new BluetoothViewHolder(view1);

    }

    @Override
    public void onBindViewHolder(@NonNull BluetoothViewHolder holder, int position) {
        BluetoothDeviceModel deviceModel = data.get(position);

        String name = data.get(position).getName();
        String address = data.get(position).getAddress();
        int imgresource = data.get(position).getImageresouce();

        holder.dropdownImgPD.setImageResource(imgresource);

        if (name == null) {
            holder.deviceNamePD.setText(address);
        } else {
            holder.deviceNamePD.setText(name);
        }

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Don't rely on the position parameter since it ca be changed when scrolling screen
                final index = holder.getAbsoluteAdapterPosition();
                // Bound check
                if (index < 0 || index >= devices.size()) {
                    Log.d("Adapter: A selection has made but couldn't get a valid index");
                    return;
                }
                final BluetoothDeviceModel deviceModel = devices.get(index);
                // ArrayLists can store null objects, check it is not null
                if (deviceModel == null) {
                    Log.d("Adapter: Selected device is null. Index is "+index);
                    return;
                }
                // Finally we can propagate the selected device safely
                if (selectListener != null) selectListener.onDeviceSelected(deviceModel);
            }
        };

        holder.cardViewPD.setOnClickListener(listener);

    }
    @Override
    public int getItemCount() {
        return data.size();
    }

    public void addDevice(BluetoothDeviceModel newDeviceModel) {
        // First check if a device with the same address already exist
        for(BluetoothDeviceModel device: devices) {
            if(device.getAddress().equals(newDeviceModel.getAddress())) {
                // This device already exist, don't proceed
                return;
            }
        }
        Log.d("Adapter: A new device will be added with address "+newDeviceModel.getAddress());
        devices.add(newDeviceModel);
        // Notify the data set changed
        notifyItemInserted(devices.size() - 1);
    }
}

Kozmotronik
  • 2,080
  • 3
  • 10
  • 25
  • Hi, I Appreciate you taking out time to provide a Solution to the Issue and Various Others, for Sure I will make the changes and Test the Code , and let you Know as Soon as Possible. – joash deoghare Jul 10 '23 at 05:05